Josh Smith

I thought I had the whole WPF data binding system down cold. Today I stumbled across something which threw me back out to sea. According to my understanding of the data binding system in WPF, an object must somehow notify the "outside world" when one of its properties is changed if it wants the new value to appear in the UI. Either it can raise a PropNameChanged event, implement INotifyPropertyChanged and raise PropertyChanged, or implement the property as a dependency property. So far, so good. However...

I was playing around with some code to answer a fellow's question on this forum, and found that a property which has no change notification in place appeared to be "notifying" the binding system that it was updated. I suspect that this might be some internal housekeeping logic in WPF, but cannot for the life of me remember ever reading about this feature. Here's my setup:

Code Snippet

public class Person

{

string name;

public string Name

{

get { return name; }

set { name = value; }

}

}

Code Snippet

<StackPanel>

<StackPanel.DataContext>

<local:Person Name="Ludwig" />

</StackPanel.DataContext>

<TextBlock Text="{Binding Name}" />

<TextBox Text="{Binding Name}" />

<Button>Steal Focus</Button>

</StackPanel>

If you edit the name of the Person in the TextBox and then move input focus to the Button, the TextBlock's Text changes to the new name! I don't get it. Does the binding system keep track of all properties bound to the Name property on my Person object and then update them automatically when the property is modified from the UI Is this documented somewhere

Thanks for any tips.




Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

lee d

DataContextChanged Event is raised and it affects all the elements which inherits the datacontext and all the databound properties are updated




Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

Josh Smith

I have a follow-up question. If all databound properties are updated when the DataContext changes, why doesn't the NameVersion property below get updated when the Name is updated

Code Snippet

public class Person

{

int nameVersion = 0;

string name;

public string Name

{

get { return name; }

set { name = value; ++this.nameVersion; }

}

public int NameVersion

{

get { return nameVersion; }

}

}

Code Snippet

<StackPanel>

<StackPanel.DataContext>

<local:Person Name="Ludwig" />

</StackPanel.DataContext>

<TextBlock Text="{Binding NameVersion}" />

<TextBlock Text="{Binding Name}" />

<TextBox Text="{Binding Name}" />

<Button>Steal Focus</Button>

</StackPanel>

Since NameVersion is incremented when Name is set, shouldn't the new NameVersion value be displayed when the new Name value is displayed






Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

Douglas Stockwell

I'm not so sure DataContextChanged is responsible, I think the magic lies in the binding system's use of PropertyDescriptor (SetValue presumably raises a ValueChanged - the PropertyDescriptor is likely shared, while the events are raised on a per-object basis).



Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

lee d

Can you try using a setter, I cannot test it myself now




Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

Josh Smith

Thanks Doug. That sounds right. Could someone at Microsoft please confirm this Thanks.




Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

Tim Dawson

I'm not at Microsoft, but I can confirm it. If PropertyDescriptor is used to update the value, as it will be, then relevant change notifications are automatically propagated.




Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

Josh Smith

Thanks for the confirmation Tim.






Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

Spaccabit

Code Snippet

public class Person : INotifyPropertyChanged

{

int nameVersion = 0;

string name;

public string Name

{

get { return name; }

set {

name = value; ++this.nameVersion;

OnDataChanged("NameVersion");

}

}

public int NameVersion

{

get { return nameVersion; }

}

#region INotifyPropertyChanged Members

[field:NonSerialized]

public event PropertyChangedEventHandler PropertyChanged;

/// <summary>

/// Called when [data changed].

/// </summary>

/// <param name="PropertyName">Name of the property.</param>

protected virtual void OnDataChanged(string PropertyName)

{

if (PropertyChanged != null)

PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));

}

#endregion

}





Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

Josh Smith

Spaccabit,

How to implement property change notification is not the topic of this thread. Anyways, thanks for the snippet.






Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

arkhivania

maby there is "by reference optimization" try this

Code Snippet

public string Name

{

get { return (string)name.Clone(); }

set { name = value; ++this.nameVersion; }

}





Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

Josh Smith

Thanks arkhivania. As Doug pointed out earlier in this thread, the behavior I mentioned can be traced back to the binding system's use of PropertyDescriptors to set the value on the data object. Since a PropertyDescriptor is mostly concerned with a property, not the property's value, cloning the Name string makes no difference.




Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

lee d

just to make sure that I understand this DataContext thing, what causes DataContextChanged event to be fired and what needs to change




Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

Josh Smith

lee,

I've been doing some experiments around this topic. DataContextChanged is raised when the DataContext property is set on an element, or on an element's ancestor in the logical tree. It is not raised when a property on the DataContext object is modified. Here's my experiment:

The data object is of type Person:

Code Snippet

public class Person : INotifyPropertyChanged

{

string name;

public string Name

{

get { return name; }

set

{

name = value;

if( this.PropertyChanged != null )

this.PropertyChanged(

this, new PropertyChangedEventArgs( "Name" ) );

}

}

public event PropertyChangedEventHandler PropertyChanged;

}

Here's the code which modifies the DataContext:

Code Snippet

public Window1()

{

InitializeComponent();

StackPanel root = this.Content as StackPanel;

this.DataContextChanged += Window1_DataContextChanged;

root.DataContextChanged += StackPanel_DataContextChanged;

Person p = new Person();

this.DataContext = p;

p.Name = "Josh";

this.DataContext = null;

root.DataContext = p;

}

void Window1_DataContextChanged(

object sender, DependencyPropertyChangedEventArgs e )

{

Debug.WriteLine( "Window: " + e.NewValue );

}

void StackPanel_DataContextChanged(

object sender, DependencyPropertyChangedEventArgs e )

{

Debug.WriteLine( "StackPanel: " + e.NewValue );

}

Here's the output of running the app, in the Output window:

Code Snippet

Window: WPF_Test.Person

StackPanel: WPF_Test.Person

Window:

StackPanel:

StackPanel: WPF_Test.Person

Notice that the DataContextChanged event handlers are only called when the DataContext property is set, not when the Person's Name property is set to a new value.






Re: Windows Presentation Foundation (WPF) How does the data binding system know when a property is changed?

lee d

Thanks. I would tend to think from the name of the event it gives the impression that it will be called if there is a change in object to which is bound also. obviously thats not the case