Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 什么触发DependencyProperties中的更改通知?_C#_Wpf_Data Binding - Fatal编程技术网

C# 什么触发DependencyProperties中的更改通知?

C# 什么触发DependencyProperties中的更改通知?,c#,wpf,data-binding,C#,Wpf,Data Binding,我正在探索C#中的数据绑定,希望了解对属性(由依赖属性支持)的哪种更改实际上会触发对绑定目标的更新通知 对于测试,我使用一个简单的类设置,可以在其中测试对嵌套属性(子属性)的更改: 现在我将BestFriendProperty(作为源)绑定到另一个类的Person属性。我希望只有在使用BestFriend的setter时,通过此绑定的更新通知才会起作用: myBoundFriends.BestFriend = new Person(); // myBoundFriends is of type

我正在探索C#中的数据绑定,希望了解对属性(由依赖属性支持)的哪种更改实际上会触发对绑定目标的更新通知

对于测试,我使用一个简单的类设置,可以在其中测试对嵌套属性(子属性)的更改:

现在我将BestFriendProperty(作为源)绑定到另一个类的Person属性。我希望只有在使用BestFriend的setter时,通过此绑定的更新通知才会起作用:

myBoundFriends.BestFriend = new Person(); // myBoundFriends is of type Friends
但我发现,即使直接更改(嵌套的)Name属性也会触发通知,并同步到绑定目标:

myBoundFriends.BestFriend.Name = "Otto"; // why does this trigger update?
数据绑定对我来说似乎有点神秘。事实上,我认为只有Freezable对象(广泛用于WPF)能够在其任何子属性更改时触发更新


编辑:当我向绑定添加一个简单的人对人转换器时,通知机制按预期工作:

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

请注意,转换器通过复制名称字符串对Person对象进行深度复制。我想这可能是解决方案的一个相关点。

这是您的问题,您的数据模型没有实现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,但这太过分了。我通常有一个实现viewmodels和datamodels接口的基类


是的,我是一个重弹迷;)

问题中的Person.Name属性不会触发源为Friends.BestFriend的绑定的更新。您的代码中还有其他一些东西导致了更新,您错误地认为是通过将“Otto”指定给Name属性触发的,我想……是的,这正是重点。我本以为已经理解了数据绑定,但这个测试用例让我感到困惑。您是否有进一步的想法或提示如何调试场景以了解发生了什么?您需要检查与这些数据绑定相关的所有源代码和/或可以创建Person对象的源代码(并研究在何种情况下会发生这种情况)。如果梳理源代码太困难或麻烦,请在Person的构造函数中设置一个断点,以跟踪创建Person对象的人。如果没有为Person声明构造函数,为了解决问题,请实现一个空的默认构造函数,您可以在该构造函数上设置断点。如果发现问题与Person对象的创建无关,然后你需要彻底研究你的源代码和程序流程——你的代码可以做的事情至少有很多种不同的可能性,就像剥猫皮的方法一样……@elgonzo:添加一个能够深度复制Person对象的Person-to-Person转换器可以使通知机制按预期工作,并且子属性更改不再触发更新,但我不明白为什么?!我猜你误解了我的问题。在这两种情况下,我都会收到更改通知:通过绑定DP的setter进行更改,以及更改绑定DP的子属性。我只希望在第一种情况下通过更改setter触发通知!显示您的xaml。从代码看,您似乎绑定到Person类上的Name属性,如前所述,它没有INotifyPropertyChanged或(blah)使Person数据模型成为DP的DO。如果不这样做,当Name属性更改时,您的UI将不会收到信号。。。。。。您必须对所有嵌套类执行此操作!或者非常懒惰,通过手动调用IE PropertyChanged(这是一个新的PropertyChangedEventArgs(String.Empty))使代码变得混乱,这将重新评估每个绑定并强制重新绘制。我这里没有任何XAML代码,这是一个最小的非UI测试用例。
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));
    }
}