为什么绑定更新没有实现INotifyPropertyChanged?

时间:2011-10-14 11:54:44

标签: wpf xaml data-binding

我创建了一个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; }
}

3 个答案:

答案 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;