2012-04-05 12 views
-1

は、私はこれをやっていた:Getterで独自のプロパティにPropertyChangedを呼び出すときの動作?

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ゲッターはそれ自身を呼び出し続けるでしょう。しかし、奇妙なことはは起こりません。

は、その後、私は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"); 
    } 
} 

あなたが行く、この時間は無限ループです。 しかし、なぜ最初のケースでは起こりませんか?

P.私はプログラムを中断しようとしていない、ちょうど私はいくつかの他の人々のプログラムをデバッグしている、彼らは最初のケースのようにここで何か類似していた。しかし、このプロパティは2回目の呼び出しではありません。

UPDATE:テストケース2について のStackTrace:

私は、テキストボックスに、このプロパティを結合することによってそれをテストし、FirstNameゲッターにブレークポイントを設定し、私はブレークポイントが倍の無限hittedされて見ることができました。

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...... 
+0

プロパティの値が変更されていないため、ゲッターでイベントを発生させるべきではありません。それはセッターでのみ発生する必要があります。 – Bernard

+0

@Bernardこのコードは問題を単純化するためのものです。その人はゲッターの中でイベントを起こして値を変更する何かをしています。 –

+4

悪いデザイン私は恐れています。 getter内のプロパティの値を変更しないでください。 – Bernard

答えて

2

PropertyChangedイベントは、プロパティの値が変更されたときに発生するように設計されています。 getter内でイベントを発生させるのは間違っていますが、無限ループは発生せず、プロパティの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だけでなく)は、タイプがINotifyPropertyChangedのオブジェクトにバインドするオブジェクトのPropertyChangedイベントをサブスクライブします。これは、コードビハインドオブジェクトからUIコントロールに状態更新を伝播する方法を管理する方法です。サブスクライブされたイベントハンドラでは、明らかにSilverlightはプロパティの新しい値を取得する必要があり、プロパティgetterを呼び出して無限ループを呼び出すことができます。

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

+0

はい、コードによって無限ループが発生します。しかし、2回目のテストでのイベント予約ですか?しかし、私は両方のテストを行うとき、私は上記のchanagesを除いて同じコードでそれをしました。 –

+0

2番目の例で無限ループが起こっていると判断するにはどうすればよいですか?スタックトレースを表示してもらえますか? – Douglas

+0

ケース2をテストすると、私はFirstNameゲッターにブレークポイントを設定します。同じブレークポイントを何度も何度も繰り返していることがわかります。ケース2のスタックトレースを更新します。 –

関連する問題