Problem with INotifyPropertyChanged

First, I want to say that the example below is simplification. Suppose you have linked a WPF control.

<Window Title="Window1" Height="300" Width="300"> <Grid> <StackPanel> <TextBox Text="{Binding Name}" Margin="10"/> <Button HorizontalAlignment="Center" Content="Click Me" Margin="5" Padding="2" Click="OnButtonClick" /> </StackPanel> </Grid> </Window> 

The window is bound to the Person class, which implements INotifyPropertyChanged and has a name installer in the form

  public string Name { get { return _name; } set { _name = "Some Name"; OnPropertyChanged("Name"); } } 

those. _name is assigned to "Some Name" whenever a user tries to change it from the user interface. But this sample does not work. I changed the name in the TextBox to some value by clicking on the tab, forcing the focus to move to the Button, and the value in the TextBox remains unchanged, although the PropertyChanged event was raised.

Could you explain to me why this is happening? Since I understand that the PropertyChanged event forces the UI to re-read the values ​​from the properties and display them, but in my example, the value in the text field with the database binding is not updated.


Yet again. I understand that this is a poor implementation of the property, but I want to repeat that this is a simplification. This is just a sample. But in any case, PropertyChanged signals that the property has been changed and needs to be updated, but this is not so.

+6
data-binding wpf inotifypropertychanged
source share
7 answers

The PropertyChanged event is ignored by the TextBox because it is the initiator of the event.

Some explanations:

A TextBox (or a binding in a text field) knows that it is the initiator because it receives the PropertyChanged event in the same call. When making an asynchronous call, the text field (or binding) is not able to know that it is the initiator, so it will process the event as if someone had updated it.

If you add a 2nd text block to your interface, you will see that the 2nd text block changes when you edit the 1st and vice versa.

+8
source share

The dummy workaround proposed by Heinzi (described here ) does not work when the UpdateSourceTrigger binding is PropertyChanged. But what if this is what we need?

It seems that creating an asynchrounous binding does the trick, for example:

 SelectedIndex="{Binding SelectedIndex, IsAsync=True}" 
+4
source share

As Bubblewrap has already pointed out, this is by design - the text field assumes that if it sets the bound property to some value, setter will not change the value. According to Microsoft, they will not change this behavior, as this will violate existing code.

If you want to change the value (yes, there are absolutely good reasons for this), you should use a workaround, for example, by adding a dummy converter. There is a blog entry (not written by me) detailing this technique.

+2
source share

The reason is because you hardcoded "Some Name" in the installer. When you change the value of textBox, the setter is actually called, and it again sets β€œSome Name” as propertyValue, so it does not change in the user interface. Put _name = value and everything will work as you expected

0
source share

If I'm not mistaken, the default binding behavior for the Text property in the TextBox is TwoWay, so this should work. You can make it be TwoWay in XAML as follows:

 <Window Title="Window1" Height="300" Width="300"> <Grid> <StackPanel> <TextBox Text="{Binding Name, Mode=TwoWay}" Margin="10"/> <Button HorizontalAlignment="Center" Content="Click Me" Margin="5" Padding="2" Click="OnButtonClick" /> </StackPanel> </Grid> </Window> 

Note Mode=TwoWay in the binding declaration.

If this does not work, then I suspect that an exception is raised in the code that triggers the event or assigns a property, and you should look for it.


It seems likely that you are making a call to change the value in a thread that is not a UI thread. If so, then you need to either march the call to trigger a property change event in the user interface thread, or make a change to the value in the user interface thread.

When an object is bound to a user interface element, changes to the object that may affect the user interface must be made in the user interface thread.

0
source share
 public string MyField { get { return _myField; } set { if (_myField == value) return; _myField = value; OnPropertyChanged("MyField"); } } 

This is the correct implementation of the property.

When you change a property, make sure that the EXACTLY same instance of the object is bound to the control. Otherwise, the change will be notified, but the control will never receive it because the control is not bound properly.

0
source share

Replacing setter in form

  set { _name = "Some Name"; Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.DataBind, (SendOrPostCallback)delegate { OnPropertyChanged("Name"); }, null); } 

fixes the problem, but it is still open. Why should I change my property instead of an asynchronous call instead of a synchronous alarm?

0
source share

All Articles