我创建了一个ViewModel,并将其属性绑定到UI上的两个文本框。当我更改first和焦点从文本框的值时,另一个文本框的值会更改,但我没有实现INotifyPropertyChanged。这是怎么回事?
以下是XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Name}" />
</StackPanel>
</Window>
以下是我的ViewModel
class ViewModel
{
public string Name { get; set; }
}
答案 0 :(得分:49)
我测试过,你是对的。现在我在网上搜索了它,找到了this。
很抱歉花了这么长时间回复,实际上你遇到了WPF的另一个隐藏方面,那就是WPF的数据绑定引擎将数据绑定到PropertyDescriptor实例包装source属性,如果源对象是纯CLR对象并且未实现INotifyPropertyChanged 接口。数据绑定引擎将尝试通过PropertyDescriptor.AddValueChanged()方法订阅属性更改事件。当目标数据绑定元素更改属性值时,数据绑定引擎将调用PropertyDescriptor.SetValue()方法将更改后的值传回源属性,并且它将同时引发ValueChanged事件以通知其他订阅者(在本例中,其他订阅者将是ListBox中的TextBlock。
如果您正在实施INotifyPropertyChanged,那么您完全有责任在需要绑定到UI的数据的每个属性集中实现更改通知。否则,更改将不会像您期望的那样同步。
希望这会让事情稍微清楚一点。
所以基本上你可以做到这一点,只要它是一个普通的CLR对象。相当整洁但完全出乎意料 - 我在过去几年里做了一些WPF工作。你永远不会停止学习新事物,对吗?
根据Hasan Khan的建议,这里有一篇非常有趣的文章another link。
注意仅在使用绑定时才有效。如果您从代码更新值,则不会通知更改。 [...]
WPF在绑定时使用重量更轻的PropertyInfo类。如果显式实现INotifyPropertyChanged,则所有WPF需要调用PropertyInfo.GetValue方法来获取最新值。这比获取所有描述符要少得多。描述符的最终成本是属性信息类的内存的4倍。 [...]
实现INotifyPropertyChanged可能是一项繁琐的开发工作。但是,您需要权衡WPF应用程序的运行时占用空间(内存和CPU)。 自己实现INPC将节省运行时CPU和内存。
答案 1 :(得分:1)
我可以解释为什么在焦点更改时更新属性:所有Binding
都有UpdateSourceTrigger
属性,指示何时将更新源属性。每个DependencyProperty
都定义了默认值,TextBox.Text
属性的默认值设置为LostFocus
,这意味着当控件失去焦点时属性将会更新。
我相信UrbanEsc的答案解释了为什么价值会更新
答案 2 :(得分:1)
我刚刚发现这也适用于WinForms,有点:/
public class Test
{
public bool IsEnabled { get; set; }
}
var test = new Test();
var btn = new Button { Enabled = false, Text = "Button" };
var binding = new Binding("Enabled", test, "IsEnabled");
btn.DataBindings.Add(binding);
var frm = new Form();
frm.Controls.Add(btn);
test.IsEnabled = true;
Application.Run(frm);
奇怪的是,这并没有禁用按钮:
btn.Enabled = false;
这样做:
test.IsEnabled = false;