-1

我正在这样做:

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 属性更改。我原以为这将是一个无限循环,FirstNamegetter 将继续调用自己。但奇怪的是并没有发生。

然后我尝试将 raise 属性更改放在里面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");
    }
}

好了,这次是无限循环。 但是为什么在第一种情况下没有发生呢?

PS我不是想破坏程序,只是我在调试其他人的程序,他们在这里做的事情就像第一个案例一样。但该物业没有被第二次调用。

更新:测试用例 2 的 StackTrace:

我通过将此属性绑定到 TextBox 并在FirstNamegetter 上设置断点来测试它,我可以看到断点被无限次命中。

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......
4

1 回答 1

2

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

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

即使在您的代码的第一个版本中,下面非常典型的示例也会导致无限循环:

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

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

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

但是,我确实相信,如果您使用属性的第一个定义(没有BackgroundWorker)并将对象绑定到TextBox.

于 2012-04-05T18:51:03.723 回答