Strange PropertyChanged UpdataSourceTrigger behavior in WPF

I have an object like this:

public class Person { public string Name { get; set; } public Person() { Name = "Godspeed"; } } 

Then I have three text fields and a button in 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> 

The strange thing is that the "Face" entity does not implement INotifyPropertyChanged, but when one text field is changed, it changes the source (Person object), but we did not raise the event with the changed property, but the other two text fields automatically change.

When the button is clicked, we update the source directly using the code, for example:

 ((Person)DataContext).Name = "Godspeed"; 

It is not updated. Therefore, I believe that if the Person class implements INotifyPropertyChanged, this behavior is normal, but now the class does not implement the interface, but it also updates the interface. Please tell me the reason if you have any clue. Thanks.

+4
source share
3 answers

The reason is PropertyDescriptor, see the following thread asking the same question: How does the data binding system know when a property is changed?

Here are two answers.

I think the magic is to use the PropertyDescriptor binding system (SetValue seems to increase the value of ValueChanged - the PropertyDescriptor will most likely be shared, while events will be for each object).


I am not at Microsoft, but I can confirm it. If the PropertyDescriptor is used to update the value, as it will, then the corresponding notification change is automatically propagated.

Edit
You can verify this by calling the Person DataContext object

 <Window.DataContext> <local:Person x:Name="person"/> </Window.DataContext> 

and add the following code to MainWindow ctor

 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"); } 

As soon as you change the value on any of the three text fields, you will be taken to the OnPropertyChanged event handler.

+4
source

Well, as you said, you just need to implement INotifyPropertyChanged

The PropertyChanged event is used when you set a property from code and must reflect this change in your user interface (the user interface will display the PropertyChanged event and the user interface will be updated thanks to your UpdateSourceTrigger ). The other side (changed from the user interface) does not need PropertyChanged , so you get this behavior

Just try this:

  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"); } } } 

Using this code, when you set the name, the PropertyChanged event will be fired and, accordingly, will update the interface :)

+1
source

It works not only with updateourcetrigger = propertychanged, but also with the default value (lost focus). In addition to what @Meleak said, I want to point out that this is good behavior. Any changes made by ui apply to all binding targets. The binding engine wants to propagate these changes to all controls at once. If you make changes through the code and do not implement INotifyPropertyChanged, changes made from the code are not reflected at all. Again, for all controls with the same binding source. All controls work synchronously with such an implementation.

+1
source

All Articles