バージョン

プロパティ変更通知

広範なオブジェクト モデル(グリッドやツリー コントロールなど)を提供しているコントロールでは、サブオブジェクトのプロパティを変更しても、内部状態の更新や表示のリフレッシュが時おり動作しないなどといったエラーに悩まされることがあります。

このようなバグを解消するためのコードをコントロール全体に記述する際に、複数のプロパティ セット ルーチンでコードが重複してしまうことがよくあります。このようなコードは極端にエラーを起こしやすいだけでなく、コントロールのサイズを不必要に大きくする原因となります。

たとえば、グリッド コントロールが Band オブジェクトのコレクションを公開し、各 Band オブジェクトが Column オブジェクトのコレクションを公開し、各 Column オブジェクトがそれぞれ Header オブジェクトを提供し、Header オブジェクトが Appearance オブジェクト プロパティを持っているとします。ここで、Appearance の ForeColor プロパティを青に設定すると、その列のヘッダ内のテキストも青に再描画されます。この場合、ヘッダだけが再描画されるのが理想的です。しかし、Appearance オブジェクト(共有アセンブリに実装されています)では列ヘッダに関することは何もわかりません。したがって、Appearance プロパティを持つオブジェクトはすべて、Appearanceプロパティが変更されたときに呼び出される自分自身のリフレッシュ ロジックを追加しなければならないことになります。このような問題を解決するための簡単な方法の 1 つに、何らかの変更が生じたときに常にコントロール全体をリフレッシュする、という方法があります。

しかし、この方法は過度のリフレッシュを生じることがあり、通常はランタイムに不必要なオーバーヘッドを招きます。プレゼンテーション層フレームワークでは、イベントベースのインフラストラクチャを提供することによってこの問題を解決しています。

このインフラストラクチャでは、サブオブジェクトの状態変更通知をオーナーシップ チェーンの上位に容易に伝達すると共に、完全な変更コンテキスト情報を保持することが可能です。

上の例では、イベントの流れは次のようになります。

  1. Appearance オブジェクトの ForeColor の設定ロジックによって NotifyPropChange というメソッドが呼び出されます。このとき、ForeColor プロパティを示す識別子が渡されます。

  2. Header オブジェクトの OnSubObjectPropertyChange メソッドが呼び出されます(Header オブジェクトが、Appearance オブジェクトにより提供されているプロパティ変更イベントをフックしたため)。このとき、上で説明した識別子を含むコンテキスト情報と、Appearance オブジェクト参照が渡されます。次に、Appearance プロパティを示す識別子と渡されたコンテキスト情報を指定して NotifyPropChange を呼び出すことにより、Header オブジェクトから通知が渡されます。注:NotifyPropertyChange メソッドは、このコンテキスト情報を先に連結してからイベントを発生させます。

  3. Column から ColumnsCollection、Band、BandsCollection へと、オーナーシップ チェーンの上位に向かって手順 2 が繰り返され、最終的にグリッド コントロールに達します。このとき、これらの各オブジェクトの OnSubObjectPropertyChange メソッドが順に呼び出されます(コンテキスト チェーンが長くなります)。グリッドに通知が渡されると、完全なコンテキスト情報を持つ PropertyChanged イベントが発生します。

利点

  • 更新/リフレッシュ ロジックを通知チェーン内のどこにでも置くことができます。そのため、不要な重複ロジックを回避できます。

  • 完全なコンテキスト情報がコンテキスト チェーンを通じて保持されるため、不必要な更新を容易に避けることができ、更新ロジックを必要に応じて詳細に制御できます。

  • コントロールのユーザーが通知チェーンをいつでもフックし、コントロールの状態変更を(完全なコンテキスト情報と共に)監視できます。