サーバー側 UI オートメーション プロバイダーの実装

Note

このドキュメントは、System.Windows.Automation 名前空間で定義されているマネージド UI オートメーション クラスを使用する .NET Framework 開発者を対象としています。 UI オートメーションの最新情報については、Windows Automation API の「UI オートメーション」を参照してください。

このセクションでは、カスタム コントロールのサーバー側 UI オートメーション プロバイダーを実装する方法について説明します。

Windows Presentation Foundation (WPF) の要素と WPF 以外の要素 (Windows フォーム向けに設計された要素など) の実装は、根本的に異なります。 WPF の要素には、AutomationPeer からの派生クラスを介した UI オートメーションのサポートが用意されています。 WPF 以外の要素では、プロバイダー インターフェイスの実装を通じてサポートが提供されます。

セキュリティに関する考慮事項

プロバイダーは、部分的に信頼された環境で動作できるように記述する必要があります。 UIAutomationClient.dll は部分的な信頼で動作するように構成されていないため、プロバイダーのコードではこのアセンブリを参照しないでください。 参照している場合、完全に信頼された環境ではコードを実行できますが、部分的に信頼された環境では失敗します。

具体的には、 AutomationElementなどの UIAutomationClient.dll のクラスのフィールドを使用しないでください。 代わりに、 AutomationElementIdentifiersなどの UIAutomationTypes.dll のクラスの同等のフィールドを使用します。

Windows Presentation Foundation 要素によるプロバイダーの実装

このトピックの詳細については、「 WPF カスタム コントロールの UI オートメーション」を参照してください。

非 WPF 要素によるプロバイダーの実装

WPF フレームワークの一部ではないが、マネージド コードで記述されたカスタム コントロール (多くの場合、Windows フォーム コントロール) は、インターフェイスを実装することで UI オートメーションをサポートします。 すべての要素は、次のセクションの最初のテーブルに示されているインターフェイスを 1 つ以上実装する必要があります。 さらに、要素が 1 つ以上のコントロール パターンをサポートする場合、コントロール パターンごとに適切なインターフェイスを実装する必要があります。

UI オートメーション プロバイダー プロジェクトは、次のアセンブリを参照する必要があります。

  • UIAutomationProviders.dll

  • UIAutomationTypes.dll

  • WindowsBase.dll

プロバイダーのインターフェイス

すべての UI オートメーション プロバイダーは、次のインターフェイスのいずれかを実装する必要があります。

インターフェイス 説明
IRawElementProviderSimple コントロール パターンやプロパティのサポートを含む、ウィンドウでホストされる単純なコントロールの機能を提供します。
IRawElementProviderFragment IRawElementProviderSimple から継承されます。 フラグメント内のナビゲーション、フォーカスの設定、要素の四角形領域の復帰などを含む、複雑なコントロールの要素の機能を追加します。
IRawElementProviderFragmentRoot IRawElementProviderFragment から継承されます。 指定した座標での子要素の検索やコントロール全体のフォーカス状態の設定などを含む、複雑なコントロールのルート要素の機能を追加します。

次のインターフェイスは追加機能を提供しますが、実装する必要はありません。

インターフェイス 説明
IRawElementProviderAdviseEvents プロバイダーがイベントの要求を追跡できるようにします。
IRawElementProviderHwndOverride フラグメントの UI オートメーション ツリー内のウィンドウ ベースの要素の位置を変更できるようにします。

System.Windows.Automation.Provider 名前空間内の他のすべてのインターフェイスは、コントロール パターンをサポートします。

非 WPF プロバイダーの要件

UI オートメーションと通信するために、コントロールは次の主な領域の機能を実装する必要があります。

機能 実装
プロバイダーを UI オートメーションに公開する コントロール ウィンドウに送信された WM_GETOBJECT メッセージの応答として、 IRawElementProviderSimple (または派生インターフェイス) を実装するオブジェクトを返します。 フラグメントの場合、これはフラグメント ルートのプロバイダーである必要があります。
プロパティ値を指定する 値を指定またはオーバーライドする GetPropertyValue を実装します。
クライアントがコントロールと対話できるようにする IInvokeProviderなどのコントロール パターンをサポートするインターフェイスを実装します。 GetPatternProviderの実装でこれらのパターンのプロバイダーを返します。
イベントを発生させる AutomationInteropProvider のメソッドの 1 つを呼び出して、クライアントがリッスンできるイベントを発生させます。
フラグメント内のナビゲーションとフォーカス設定を有効にする フラグメント内の各要素に IRawElementProviderFragment を実装します (フラグメントの一部でない要素に対しては必要ありません)。
フラグメント内のフォーカス設定と子要素の配置を有効にする IRawElementProviderFragmentRootを実装します。 (フラグメント ルートでない要素に対しては必要ありません)。

非 WPF プロバイダー内のプロパティ値

カスタム コントロールの UI オートメーション プロバイダーは、オートメーション システムおよびクライアント アプリケーションで使用できる特定のプロパティをサポートする必要があります。 ウィンドウでホストされている (HWND) 要素の場合、UI オートメーションは一部のプロパティを既定のウィンドウ プロバイダーから取得できますが、他のプロパティはカスタム プロバイダーから取得する必要があります。

HWND ベースのコントロールのプロバイダーは通常、次のプロパティを指定する必要はありません (フィールド値で識別されます)。

Note

単純な要素またはウィンドウでホストされているフラグメント ルートの RuntimeIdProperty は、ウィンドウから取得されます。ただし、ルートの下にあるフラグメント要素 (リスト ボックス内のリスト項目など) は独自の識別子を提供する必要があります。 詳細については、「GetRuntimeId」を参照してください。

Windows フォーム コントロールでホストされているプロバイダーには、IsKeyboardFocusableProperty が返される必要があります。 この場合、ウィンドウの既定のプロバイダーは適切な値を取得できないことがあります。

NameProperty は通常、ホスト プロバイダーによって提供されます。 たとえば、カスタム コントロールが Controlから派生している場合、名前はこのコントロールの Text プロパティから派生します。

コード例については、「 UI オートメーション プロバイダーからのプロパティの返却」を参照してください。

非 WPF プロバイダー内のイベント

UI オートメーション プロバイダーは、イベントを発生させて、UI の状態の変更をクライアント アプリケーションに通知する必要があります。 イベントを発生させるには、次のメソッドを使用します。

方法 説明
RaiseAutomationEvent コントロール パターンによってトリガーされるイベントを含む、さまざまなイベントを発生させます。
RaiseAutomationPropertyChangedEvent UI オートメーション プロパティが変更された場合にイベントを発生させます。
RaiseStructureChangedEvent 要素の追加や削除などによって UI オートメーション ツリーの構造が変更された場合にイベントを発生させます。

イベントの目的は、UI オートメーション システム自体によってトリガーされたアクティビティかどうかにかかわらず、何かがユーザー インターフェイス (UI) 内で行われたことをクライアントに通知することです。 たとえば、 InvokedEvent によって識別されるイベントは、ユーザーの直接入力の場合でもクライアント アプリケーションの Invoke呼び出しの場合でも、コントロールが呼び出されるたびに発生させる必要があります。

パフォーマンスを最適化するため、プロバイダーは選択的にイベントを発生させたり、イベントを受け取るクライアント アプリケーションが登録されていないときにはイベントを発生させないようにすることができます。 最適化には、次のメソッドを使用します。

方法 説明
ClientsAreListening この静的プロパティは、クライアント アプリケーションが UI オートメーション イベントにサブスクライブしているかどうかを指定します。
IRawElementProviderAdviseEvents プロバイダーがこのインターフェイスをフラグメント ルートに実装すると、クライアントがフラグメント上のイベント用のイベント ハンドラーを登録および登録解除したときに通知されるようにすることができます。

非 WPF プロバイダーのナビゲーション

ウィンドウでホストされる (HWND) カスタム ボタンなどの単純なコントロールのプロバイダーは、UI オートメーション ツリー内のナビゲーションをサポートする必要はありません。 要素間のナビゲーションは、ホスト ウィンドウの既定のプロバイダーによって処理されます。これは、 HostRawElementProviderの実装で指定されます。 ただし、複雑なカスタム コントロール用のプロバイダーを実装する場合は、フラグメントのルート ノードと子孫ノード、および兄弟ノード間のナビゲーションをサポートする必要があります。

Note

ルート以外のフラグメントの要素は、HostRawElementProvider から null 参照を返す必要があります。これらが直接ウィンドウでホストされておらず、これらの間のナビゲーションをサポートできる既定のプロバイダーがないためです。

フラグメントの構造は、 Navigateの実装によって決まります。 このメソッドは、各フラグメントから可能なそれぞれの方向に対して、その方向の要素に対するプロバイダー オブジェクトを返します。 その方向に要素がない場合、メソッドは null 参照を返します。

フラグメント ルートは、子要素へのナビゲーションのみをサポートします。 たとえば、リスト ボックスは、方向が FirstChildの場合はリスト内の最初の項目を、方向が LastChildの場合は最後の項目を返します。 フラグメント ルートは、親または兄弟へのナビゲーションをサポートしません。これはホスト ウィンドウ プロバイダーによって処理されます。

ルート以外のフラグメントの要素は、親へのナビゲーションと、(存在する場合は) 兄弟や子へのナビゲーションをサポートする必要があります。

非 WPF プロバイダーの親の変更

ポップアップ ウィンドウは、実際には最上位のウィンドウであり、既定ではデスクトップの子として UI オートメーション ツリーに表示されます。 ただし、多くの場合、ポップアップ ウィンドウは論理的には他のコントロールの子になります。 たとえば、コンボ ボックスのドロップダウン リストは、論理的にはコンボ ボックスの子です。 同様に、メニューのポップアップ ウィンドウは、論理的にはメニューの子になります。 UI オートメーションはポップアップ ウィンドウの親の変更をサポートしているため、ポップアップ ウィンドウを関連するコントロールの子として表示できます。

ポップアップ ウィンドウの親を変更するには:

  1. ポップアップ ウィンドウ用のプロバイダーを作成します。 これには、ポップアップ ウィンドウのクラスを事前に知っておく必要があります。

  2. そのポップアップ自体がコントロールであるかのように、ポップアップのすべてのプロパティとパターンを通常どおりに実装します。

  3. HostRawElementProvider プロパティを実装し、 HostProviderFromHandleから取得した値を返せるようにします。パラメーターは、ポップアップ ウィンドウのウィンドウ ハンドルです。

  4. ポップアップ ウィンドウとその親の Navigate を実装し、論理上の親から論理上の子へのナビゲーションおよび子の兄弟間のナビゲーションが適切に処理されるようにします。

UI オートメーションは、ポップアップ ウィンドウを検出すると、既定のナビゲーションがオーバーライドされていると認識し、デスクトップの子として検出されたポップアップ ウィンドウをスキップします。 代わりに、ノードはフラグメントによってのみ、到達可能になります。

コントロールが任意のクラスのウィンドウをホストできる場合には、親の変更は適切ではありません。 たとえば、Rebar はそのバンド内で任意の型の HWND をホストできます。 このような場合を処理するため、UI オートメーションは次のセクションで説明する、別の形の HWND 再配置をサポートしています。

非 WPF プロバイダーの再配置

UI オートメーション フラグメントは、それぞれウィンドウ (HWND) に含まれる 2 つ以上の要素を含んでいる場合があります。 各 HWND には独自の既定のプロバイダーがあり、その HWND を含む HWND をその親と見なしているため、UI オートメーション ツリーは既定で、HWND を親ウィンドウの子としてフラグメント内に表示します。 ほとんどの場合、これは適切な動作ですが、場合によっては UI の論理構造が一致しないために混乱を招く可能性があります。

良い例が Rebar コントロールです。 Rebar はバンドを格納し、各バンドはツール バー、編集ボックス、コンボ ボックスなど HWND ベースのコントロールを格納します。 Rebar HWND の既定のウィンドウ プロバイダーは、バンド コントロール HWND を子と見なし、Rebar プロバイダーはバンドを子と見なします。 HWND プロバイダーと Rebar プロバイダーは連動し、互いの子を結合するため、バンドと HWND ベースのコントロールはどちらも Rebar の子として表示されます。 ただし、論理的には、バンドのみが Rebar の子として表示され、各バンド プロバイダーは、格納されるコントロールの既定の HWND プロバイダーと結合される必要があります。

これを実現するため、Rebar のフラグメント ルート プロバイダーは、バンドを表す子のセットを公開します。 各バンドには、プロパティとパターンを公開するプロバイダーが 1 つあります。 その HostRawElementProviderの実装で、バンド プロバイダーはコントロール HWND の既定のウィンドウ プロバイダーを返します。これを取得するには、コントロールのウィンドウ ハンドルを渡して HostProviderFromHandleを呼び出します。 最後に、Rebar のフラグメント ルート プロバイダーは IRawElementProviderHwndOverride インターフェイスを実装し、その GetOverrideProviderForHwnd の実装で、指定した HWND に含まれるコントロールの適切なバンド プロバイダーを返します。

関連項目