在Getter中将PropertyChanged提升为其自己的属性时的行为

本文关键字:属性 自己的 中将 PropertyChanged Getter | 更新日期: 2023-09-27 18:30:14

我在做这个:

public string FirstName
{
    get
    {
        //Actual Code was doing something to change the value here
        this._FirstName = "Hello";
        this.OnPropertyChanged("FirstName");
        return this._FirstName;
    }
    set {
        if (this._FirstName == value)
            return;
        this._FirstName = value;
        this.OnPropertyChanged("FirstName");
    }
}

正如您所看到的,我在FirstName属性中提出了FirstName的属性更改。我原以为这将是一个无限循环,FirstName getter将继续调用自己。但奇怪的是并没有发生

然后我尝试将募集属性更改放入BackgroundWorker:中

public string _FirstName { get; set; }
public string FirstName
{
    get
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += (sender, e) =>
            {
                Thread.Sleep(2000);
            };
        worker.RunWorkerCompleted += (sender, e) =>
            {
                this._FirstName = "Hi Hi";
                this.OnPropertyChanged("FirstName");
            };
        worker.RunWorkerAsync();
        return this._FirstName;
    }
    set {
        if (this._FirstName == value)
            return;
        this._FirstName = value;
        this.OnPropertyChanged("FirstName");
    }
}

好了,这个时间是无限循环但为什么在第一种情况下不发生呢

附言:我并没有试图破坏程序,只是我正在调试其他人的程序,他们在这里做了类似的事情,就像第一种情况一样。但这处房产并不是第二次被叫停。

更新:测试用例2:的StackTrace

我通过将此属性绑定到TextBox并在FirstName getter上设置断点来测试它,我可以看到断点被打了无数次。

at Person.get_FirstName()  
at RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)  
at RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)  
at RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)  
at RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)  
at RuntimePropertyInfo.GetValue(Object obj, Object[] index)  
at CLRPropertyListener.get_Value()  
at PropertyAccessPathStep.get_Value()  
at PropertyPathListener.ReconnectPath()  
at <>c__DisplayClass4.<BreakOnSharedType>b__3()  
at RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)  
at RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder......

在Getter中将PropertyChanged提升为其自己的属性时的行为

根据设计,PropertyChanged事件仅在属性值更改时引发。在getter中引发事件是不正确的,但它本身不会导致无限循环,甚至不会使用属性的第二个定义(使用BackgroundWorker)。

但是,当消费者订阅您的事件时,在getter中引发PropertyChanged几乎肯定会导致无限循环,因为事件处理程序通常要做的第一件事是通过其getter获取属性的新值。

下面这个非常典型的例子甚至在你的代码的第一个版本中也会导致一个无限循环:

Person person = new Person();
person.PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
{
    Console.WriteLine("New name: " + person.FirstName);
};
person.FirstName = "ABC";

我的假设是,你得到了一个无限循环,因为你有一个事件订阅,它在第二个测试中访问getter。

编辑:您正在将属性绑定到TextBox;这就解释了无限循环。在场景下,Silverlight(以及WPF)订阅任何类型实现INotifyPropertyChanged的绑定对象的PropertyChanged事件;这就是它如何将状态更新从代码隐藏对象传播到UI控件的方式。在其订阅的事件处理程序中,Silverlight显然需要检索属性的新值,并且它通过调用属性getter来实现,从而调用无限循环。

然而,我相信,如果您使用属性的第一个定义(没有BackgroundWorker)并将对象绑定到TextBox,也会发生同样的事情。