关于wpf:为什么绑定更新没有实现INotifyPropertyChanged?

Why does the binding update without implementing INotifyPropertyChanged?

我创建了一个视图模型,并将其属性绑定到UI上的两个文本框。当我更改First的值并将焦点从文本框中移开时,其他文本框的值会发生更改,但我没有实现InotifyPropertiesChanged。这是怎么工作的?

以下是XAML

1
2
3
4
5
6
7
8
9
10
11
12
13
<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>

下面是我的视图模型

1
2
3
4
class ViewModel
{
    public string Name { get; set; }
}

我测试过了,你是对的。现在我在网上找到了这个。

Sorry to take so long to reply, actually you are encountering a another hidden aspect of WPF, that's it WPF's data binding engine will data bind to PropertyDescriptor instance which wraps the source property if the source object is a plain CLR object and doesn't implement INotifyPropertyChanged interface. And the data binding engine will try to subscribe to the property changed event through PropertyDescriptor.AddValueChanged() method. And when the target data bound element change the property values, data binding engine will call PropertyDescriptor.SetValue() method to transfer the changed value back to the source property, and it will simultaneously raise ValueChanged event to notify other subscribers (in this instance, the other subscribers will be the TextBlocks within the ListBox.

And if you are implementing INotifyPropertyChanged, you are fully responsible to implement the change notification in every setter of the properties which needs to be data bound to the UI. Otherwise, the change will be not synchronized as you'd expect.

Hope this clears things up a little bit.

所以基本上你可以这样做,只要它是一个普通的clr对象。非常整洁,但完全出乎意料-我在过去几年做了一些WPF工作。你从不停止学习新事物,对吧?

正如哈桑·汗所建议的,这里有另一个链接指向一篇关于这个主题的非常有趣的文章。

Note this only works when using binding. If you update the values from code, the change won't be notified. [...]

WPF uses the much lighter weight PropertyInfo class when binding. If you explicitly implement INotifyPropertyChanged, all WPF needs to do is call the PropertyInfo.GetValue method to get the latest value. That's quite a bit less work than getting all the descriptors. Descriptors end up costing in the order of 4x the memory of the property info classes. [...]

Implementing INotifyPropertyChanged can be a fair bit of tedious development work. However, you'll need to weigh that work against the runtime footprint (memory and CPU) of your WPF application. Implementing INPC yourself will save runtime CPU and memory.


我刚发现这也适用于WinForms,有点:/

1
2
3
4
5
6
7
8
9
10
11
12
13
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);

但奇怪的是,这并不能禁用按钮:

1
btn.Enabled = false;

这样做:

1
test.IsEnabled = false;


我可以解释为什么当焦点更改时属性会更新:所有Binding的属性都有一个UpdateSourceTrigger属性,它指示何时更新源属性。此属性的默认值在每个DependencyProperty上定义,对于TextBox.Text属性,该值设置为LostFocus,这意味着当控件失去焦点时将更新该属性。

我相信Urbanesc的回答解释了价值更新的原因