我正在探索C#中的数据绑定,并希望了解属性的哪种更改(由依赖项属性支持)实际上会触发绑定目标的更新通知。
对于测试,我使用一个简单的类设置,我可以测试对嵌套属性(子属性)的更改:
// 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); }
}
}
现在我将BestFriendProperty(作为源代码)绑定到另一个类的Person属性。我希望通过此绑定的更新通知仅在我使用BestFriend的设置者时才有效:
myBoundFriends.BestFriend = new Person(); // myBoundFriends is of type Friends
但我发现,即使直接更改(嵌套)名称属性,也会触发通知并与绑定目标同步:
myBoundFriends.BestFriend.Name = "Otto"; // why does this trigger update?
数据绑定对我来说似乎有些神秘。实际上我认为只有Freezable对象(在WPF中广泛使用)能够在其任何子属性发生变化时触发更新?!
编辑:当我向绑定添加一个简单的Person to Person转换器时,通知机制按预期工作:
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));
}
}
请注意,转换器通过复制Name字符串来执行Person对象的深层复制。我想这可能是解决方案的一个相关点。
答案 0 :(得分:0)
这是您的问题,您的datamodel没有实现INotifyPropertyChanged接口。
public class Person
{
public String Name { get; set; }
}
将其更改为
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));
}
}
这将指示GUI在您的代码中更改时重绘与Name属性绑定的任何内容。或者你可以使用DO作为基类,并将Name属性设为DP,但这只是过度杀伤。我通常有一个基类来实现我的viewmodel和datamodel的接口。
是的,我是一名resharper瘾君子;)