-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 プロパティの変更を行っています。これは無限ループになると予想していましたが、FirstNameゲッターは自分自身を呼び出し続けます。しかし、奇妙なことは起こりません。

次に、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回目に呼び出されていません。

更新: テスト ケース 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イベントはプロパティの値が変更されたときにのみ発生することを意図しています。ゲッター内でイベントを発生させることは正しくありませんが、プロパティの2番目の定義(を使用BackgroundWorker)を使用していなくても、それ自体で無限ループが発生することはありません。

ただしPropertyChanged、イベントハンドラーが通常最初に行うことは、ゲッターを介してプロパティの新しい値を取得することであるため、ゲッター内でレイズすると、コンシューマーがイベントをサブスクライブするときに無限ループが発生することはほぼ確実です。

以下の非常に典型的な例では、コードの最初のバージョンでも無限ループが発生します。

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

2番目のテストでゲッターにアクセスするイベントサブスクリプションがあるため、無限ループが発生していると思います。

編集TextBox:プロパティを;にバインドしています。それは無限ループを説明しています。シーンの下で、Silverlight(およびWPF)はPropertyChanged、タイプが実装されているバインドしたオブジェクトのイベントをサブスクライブしINotifyPropertyChangedます。これが、コードビハインドオブジェクトからUIコントロールに状態の更新を伝播する方法です。サブスクライブされたイベントハンドラーでは、Silverlightは明らかにプロパティの新しい値を取得する必要があり、プロパティゲッターを呼び出して、無限ループを実行します。

ただし、プロパティの最初の定義(を使用せずにBackgroundWorker)を使用し、オブジェクトをにバインドした場合も、同じことが起こると思いますTextBox

于 2012-04-05T18:51:03.723 に答える