我有一个这样的实体:
public class Person
{
public string Name { get; set; }
public Person()
{
Name = "Godspeed";
}
}
在XAML中有三个文本框和一个按钮:
<Window x:Class="WpfApplication19.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication19"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:Person />
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" />
<Button Click="Button_Click">Click</Button>
</StackPanel>
</Window>
奇怪的是,实体"Person"没有实现INotifyPropertyChanged,但是当一个文本框被改变时,它会修改源(Person对象),但是我们没有引发property changed事件,但其余两个文本框会自动改变。
当按钮被点击时,我们直接更新源代码,代码如下:
((Person)DataContext).Name = "Godspeed";
它不更新。我认为的是,如果Person类实现了INotifyPropertyChanged,这个行为是正常的,但现在这个类不实现接口,但它也更新接口。如果你有线索,请告诉我原因。谢谢。
原因是PropertyDescriptor,参见下面的线程,同样的问题也出现了:数据绑定系统如何知道属性何时被更改?
以下是其中两个答案
我认为魔法在于绑定系统的使用PropertyDescriptor (SetValue)可能会引发一个valuechange属性描述符可能是共享的,而事件是在每个对象)。
我不在微软,但我可以证实这一点。如果PropertyDescriptor是用于更新值,然后进行相关更改通知会自动传播。
编辑
您可以通过命名Person
DataContext对象
<Window.DataContext>
<local:Person x:Name="person"/>
</Window.DataContext>
,并将以下代码添加到MainWindow
public MainWindow()
{
InitializeComponent();
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(person);
PropertyDescriptor nameProperty = properties[0];
nameProperty.AddValueChanged(person, OnPropertyChanged);
}
void OnPropertyChanged(object sender, EventArgs e)
{
MessageBox.Show("Name Changed");
}
一旦你改变了三个文本框中的任何一个的值,你将结束在事件处理程序OnPropertyChanged.
就像你说的,你只需要实现INotifyPropertyChanged
当您从代码设置属性并需要将此更改反映到您的UI时使用PropertyChanged
事件(UI将捕获PropertyChanged
事件,并且由于您的UpdateSourceTrigger
, UI将被更新)。另一边(从UI改变)不需要任何PropertyChanged
,这就是为什么你得到这个行为
就像这样试试:
public class Person : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
/// <summary>
/// Property Changed Event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Property Changed
/// </summary>
/// <param name="propertyName"></param>
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
}
使用这段代码,当您设置Name时,PropertyChanged
事件将被触发,因此将相应地更新UI:)
它不仅适用于updatesourcetrigger=propertychanged,而且适用于默认值(失去焦点)。除了@Meleak所说的,我想指出这是一种良好的行为。ui所做的任何更改都会传播到所有绑定目标。绑定引擎希望一次将此更改传播到所有控件。如果您通过代码进行更改,而不实现INotifyPropertyChanged -从代码中所做的更改根本不会反映出来。同样,对于具有相同绑定源的所有控件。所有控件都以同步的方式工作。