UIElement の抽象化は、Appearance オブジェクトと共に、プレゼンテーション層フレームワークの中核を形成しています。
UIElement はコントロールによって描画される任意の個別の領域として定義され、ひとつまたは複数の子 UIElement を含むことができます。以下の図は UltraGrid の UIElement の一部を示しています。
UIElement 基本クラスは自身のクライアント四角形と子の UIElements コレクションを維持しています。UIElement 基本クラスは、任意のコントロールで使用可能な共通の UIElement 派生クラス(TextUIElment、ButtonUIElement、ImageUIElement、SplitterUIElement など)のセットと共に、プレゼンテーション層フレームワークの共有アセンブリに実装されています。
各 UIElement 派生クラスはコンテキスト情報も維持しています(基本クラスには「PrimaryContext」という名前の保護されたプロパティがあり、通常はこちらを使用するのが適切です)。たとえば、UltraGrid において、RowUIElement は論理的に関連付けられている Row オブジェクトへの参照を維持します。同様に、CellUIElement は関連付けられた Cell オブジェクトへの参照を維持します。
注:RowUIElement は Row オブジェクトとは別のオブジェクトになっています。その理由のひとつは、(スプリッタバーによって分割された)RowScrollRegion が複数存在する場合に同じ論理行が複数のリージョンに出現する可能性があるためです。この場合、単一の Row オブジェクトを表示する RowUIElement が複数存在することになります。この仕組みによって、Row の状態が変化したときに必ずすべてのリージョンにその変更が自動的に反映されます。
ControlUIElementBase と呼ばれる特殊な抽象基本クラスもあります。コントロールのメイン エレメントは必ずこのクラスから派生されます。この ControlUIElementBase 派生エレメントは、通常はコントロールのクライアント領域全体を占有します。このクラスは、コントロールの描画や、どの要素上をマウスが通過したかを判断するためのヒットテストなどの操作において、それらの開始エレメントともなります。
さらに、ControlUIElementBase クラスはコントロールのマウス イベントとキーイベントを自動的にフックし、すべてのコントロールが提供している MouseEnterElement および MouseLeaveElement という 2 つの新しいイベントを発生させます。これにより、コントロールのユーザーは、コントロールのどの領域上をマウスが通過したのかを正確に知ることができます。
描画、ヒットテスト、マウス トラッキングなどのロジックについても、そのほとんどが共有アセンブリに実装されています。このような設計の利点は、これらの操作のほとんどが簡単な再帰ルーチンとして実装されている点にあります。たとえば、描画は ControlUIElementBase 派生エレメントの Draw メソッドを呼び出すことによって始まります。次に、DrawElement メソッドが呼び出されます。 このメソッドは、一連の仮想メソッドを呼び出すことにより、エレメントの背景、境界線、および前景を描画します。この DrawElement メソッドによる描画処理が、同じ DrawElement メソッドを呼び出す子エレメントに対して繰り返されます。このようにして、階層状の自然な描画アルゴリズムが実行されます。
UIElement 基本クラスを抽象化することで、これらの操作を実行するためのすべてのロジックを共有アセンブリに収めることが可能になります。これらの UIElement 基本メソッドは、自らの操作を実行するために UIElement のいくつかの仮想メソッドおよび仮想プロパティを呼び出します。これらの動作はデフォルトで実装されていますが、派生クラスの中でオーバーライドすることもできます。
UIElement の抽象化にはさまざまな利点があります。そのいくつかを次に示します。
通常は複雑な描画やヒットテストなどの操作を、非常に簡単な再帰ルーチンに確実に実装できる。このため、動作の安定性が向上し、コード サイズが小さくなる。
前述した階層状の自然な描画アルゴリズムにより、アルファ ブレンディングなどの高度な効果を自動的にサポートできる。
詳細なマウス位置情報を提供する MouseEnterElement イベントおよび MouseLeaveElement イベントがコントロールから提供される。
ユーザーは(簡単なインタフェースを実装することで)独自の描画フィルターを設定し、任意の要素の背景、境界線、前景の描画をオーバーライドできる。
ユーザーは(別の簡単なインタフェースを実装することで)独自の子エレメント作成フィルターを設定し、任意のエレメントの子エレメントを追加したり、位置変更したり、置換したりできる。
ユーザーは(別の簡単なインタフェースを実装することで)独自のカーソル フィルターを設定し、マウスが任意のエレメント上を通過するときに使用されるカスタム カーソルを提供できる。
ユーザーは(別の簡単なインタフェースを実装することで)独自の選択方式フィルターを設定し、キーボードおよびマウスの選択ロジックをカスタマイズできる。
これらのフィルター(描画、作成、カーソル、選択方式の各フィルター)は、市販されている他のどのコントロールも備えていない、非常に強力な拡張メカニズムを公開している。
すべてのコントロールで(自分で作成したコントロールも含めて)、ロジックが共有アセンブリに実装されているため、これらの強力な機能を簡単に利用できる。
共通の UIElement 基本クラスがフレームワークに実装されており、それらもまた利用できる。たとえば、SplitterUIElement は適切なスプリッタ カーソルを供給し、ドラッグ操作中にマウスのキャプチャとスプリッタの反転を処理する。SplitterUIElement からは派生クラスを作成することが可能で、派生クラスでは ApplyAdjustment メソッドをオーバーライドするだけでよい。