Reputation: 1891
I am exploring databinding in C# and want to understand what kind of changes to a property (backed by a dependency property) actually trigger an update notification to bound targets.
For testing I use a simple setup of classes where I can test changes to nested properties (sub-properties):
// Person with a name
public class Person
{
public String Name { get; set; }
}
// Class giving the best friend as DependencyProperty
public class Friends : DependencyObject
{
public static DependencyProperty BestFriendProperty =
DependencyProperty.Register("BestFriend", typeof(Person), typeof(Friends));
public Person BestFriend
{
get { return (Person)this.GetValue(BestFriendProperty); }
set { this.SetValue(BestFriendProperty, value); }
}
}
Now I bind the BestFriendProperty (as source) to some Person property of another class. I expected that update notifications via this binding only works if I use the setter of BestFriend:
myBoundFriends.BestFriend = new Person(); // myBoundFriends is of type Friends
But I discovered that even a direct change of the (nested) Name Property triggers a notification and synchronisation to the bound target works:
myBoundFriends.BestFriend.Name = "Otto"; // why does this trigger update?
The databinding seems some kind of mysterious to me. Actually I thought that only Freezable objects (used extensively in WPF) are capable of triggering update when any of its sub-properties changes?!
Edit: The notification mechanism works as expected when I add a simple Person to Person converter to the binding:
public class PersonPersonConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Person p = (Person)value;
return new Person(String.Copy(p.Name));
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Person p = (Person)value;
return new Person(String.Copy(p.Name));
}
}
Notice that the converter does a deep copy of the Person object by copying the Name string. I guess this might be a relevant point for the solution.
Upvotes: 0
Views: 279
Reputation: 2902
Here is your problem, your datamodel does not implement the INotifyPropertyChanged interface.
public class Person
{
public String Name { get; set; }
}
Change it to
public class Person : INotifyPropertyChanged
{
private string name;
public String Name
{
get { return name; }
set
{
if (value == name) return;
name = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] // Comment out this attribute if you don't have R#
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
This will signal the GUI to redraw anything that's bound to your Name property, when it changes in your code. Alternativly you may use DO as a baseclass and make the Name property a DP, but that's just overkill. I usually have a baseclass that implements the interface for both my viewmodels and datamodels.
And yes I am a resharper addict ;)
Upvotes: 0