次の方法で共有


Windows フォームと WPF 相互運用性の入力アーキテクチャ

WPF フォームと Windows フォーム間の相互運用には、両方のテクノロジに適切なキーボード入力処理が必要です。 このトピックでは、ハイブリッド アプリケーションでの円滑な相互運用を可能にするために、これらのテクノロジでキーボードとメッセージ処理を実装する方法について説明します。

このトピックには、次のサブセクションが含まれています。

  • モードレス フォームとダイアログ ボックス

  • WindowsFormsHost キーボードとメッセージ処理

  • ElementHost キーボードとメッセージ処理

モードレス フォームとダイアログ ボックス

WindowsFormsHost 要素の EnableWindowsFormsInterop メソッドを呼び出して、WPF ベースのアプリケーションからモードレス フォームまたはダイアログ ボックスを開きます。

ElementHost コントロールで EnableModelessKeyboardInterop メソッドを呼び出し、Windows Forms ベースのアプリケーションでモードレス WPF ページを開きます。

WindowsFormsHost キーボードとメッセージ処理

WPF ベースのアプリケーションによってホストされている場合、Windows フォームのキーボードとメッセージの処理は次の要素で構成されます。

  • WindowsFormsHost クラスは、ComponentDispatcher クラスによって実装される WPF メッセージ ループからメッセージを取得します。

  • WindowsFormsHost クラスは、Windows フォームの通常のキーボード処理が確実に行われるように、代理 Windows フォーム メッセージ ループを作成します。

  • WindowsFormsHost クラスは、WPF とフォーカス管理を調整する IKeyboardInputSink インターフェイスを実装します。

  • WindowsFormsHost コントロールは自身を登録し、メッセージ ループを開始します。

以降のセクションでは、プロセスのこれらの部分について詳しく説明します。

WPF メッセージ ループからのメッセージの取得

ComponentDispatcher クラスは、WPF のメッセージ ループ マネージャーを実装します。 ComponentDispatcher クラスは、WPF がメッセージを処理する前に外部クライアントがメッセージをフィルター処理できるようにするフックを提供します。

相互運用の実装は、wpf コントロールの前にメッセージを処理する Windows フォーム コントロールを有効にする ComponentDispatcher.ThreadFilterMessage イベントを処理します。

サロゲート Windows フォーム メッセージ ループ

既定では、System.Windows.Forms.Application クラスには、Windows フォーム アプリケーションのプライマリ メッセージ ループが含まれています。 相互運用中、Windows フォーム メッセージ ループはメッセージを処理しません。 したがって、このロジックを再現する必要があります。 ComponentDispatcher.ThreadFilterMessage イベントのハンドラーは、次の手順を実行します。

  1. IMessageFilter インターフェイスを使用してメッセージをフィルター処理します。

  2. Control.PreProcessMessage メソッドを呼び出します。

  3. 必要に応じて、メッセージを翻訳してディスパッチします。

  4. 他のコントロールがメッセージを処理しない場合は、メッセージをホスティング コントロールに渡します。

IKeyboardInputSink の実装

サロゲート メッセージ ループは、キーボード管理を処理します。 したがって、IKeyboardInputSink.TabInto メソッドは、WindowsFormsHost クラスの実装を必要とする唯一の IKeyboardInputSink メンバーです。

既定では、HwndHost クラスは IKeyboardInputSink.TabInto 実装の false を返します。 これにより、WPF コントロールから Windows フォーム コントロールへのタブ移動が禁止されます。

IKeyboardInputSink.TabInto メソッドの WindowsFormsHost 実装では、次の手順を実行します。

  1. WindowsFormsHost コントロールに含まれており、フォーカスを受け取ることができる最初または最後の Windows フォーム コントロールを検索します。 コントロールの選択はトラバーサル情報によって異なります。

  2. コントロールにフォーカスを設定し、trueを返します。

  3. フォーカスを受け取ることができるコントロールがない場合は、falseを返します。

WindowsFormsHost 登録

WindowsFormsHost コントロールへのウィンドウ ハンドルが作成されると、WindowsFormsHost コントロールは、メッセージ ループの存在を登録する内部静的メソッドを呼び出します。

登録時に、WindowsFormsHost コントロールはメッセージ ループを調べます。 メッセージ ループが開始されていない場合は、ComponentDispatcher.ThreadFilterMessage イベント ハンドラーが作成されます。 メッセージ ループは、ComponentDispatcher.ThreadFilterMessage イベント ハンドラーがアタッチされたときに実行されていると見なされます。

ウィンドウ ハンドルが破棄されると、WindowsFormsHost コントロールは登録から自分自身を削除します。

ElementHost キーボードとメッセージ処理

Windows フォーム アプリケーションによってホストされている場合、WPF キーボードとメッセージ処理は次の要素で構成されます。

  • HwndSourceIKeyboardInputSink、および IKeyboardInputSite インターフェイスの実装。

  • タブキーと方向キー。

  • コマンド キーとダイアログ ボックス キー。

  • Windows フォーム アクセラレータの処理。

以降のセクションでは、これらの部分について詳しく説明します。

インターフェイスの実装

Windows フォームでは、キーボード メッセージはフォーカスのあるコントロールのウィンドウ ハンドルにルーティングされます。 ElementHost コントロールでは、これらのメッセージはホストされる要素にルーティングされます。 これを実現するために、ElementHost コントロールは HwndSource インスタンスを提供します。 ElementHost コントロールにフォーカスがある場合、HwndSource インスタンスは、WPF InputManager クラスで処理できるように、ほとんどのキーボード入力をルーティングします。

HwndSource クラスは、IKeyboardInputSink インターフェイスと IKeyboardInputSite インターフェイスを実装します。

キーボード相互運用は、OnNoMoreTabStops メソッドを実装して、ホストされている要素からフォーカスを移動する TAB キーと方向キーの入力を処理することに依存します。

タブキーと矢印キー

Windows フォームの選択ロジックは、TAB キーと方向キー ナビゲーションを実装するために、IKeyboardInputSink.TabInto および OnNoMoreTabStops メソッドにマップされます。 Select メソッドをオーバーライドすると、このマッピングが実行されます。

コマンド キーとダイアログ ボックス キー

コマンド キーとダイアログ キーを処理する最初の機会を WPF に与えるために、Windows フォーム コマンドの前処理は TranslateAccelerator メソッドに接続されます。 Control.ProcessCmdKey メソッドをオーバーライドすると、2 つのテクノロジが接続されます。

TranslateAccelerator メソッドを使用すると、ホストされる要素は、コマンド キー (TAB、ENTER、ESC、方向キーなど) を含む、WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN、またはWM_SYSKEYUPなどの任意のキー メッセージを処理できます。 キー メッセージが処理されない場合、それは処理のために Windows フォームの先祖階層を通じて送られます。

アクセラレータ処理

アクセラレータを正しく処理するには、Windows フォーム アクセラレータの処理を WPF AccessKeyManager クラスに接続する必要があります。 さらに、すべてのWM_CHARメッセージをホストされる要素に正しくルーティングする必要があります。

TranslateChar メソッドの既定の HwndSource 実装では falseが返されるため、WM_CHARメッセージは次のロジックを使用して処理されます。

  • Control.IsInputChar メソッドは、すべてのWM_CHARメッセージがホストされた要素に確実に転送されるようにオーバーライドされます。

  • Alt キーを押すと、メッセージはWM_SYSCHAR。 Windows フォームでは、IsInputChar メソッドを使用してこのメッセージを前処理しません。 したがって、ProcessMnemonic メソッドは、登録されているアクセラレータの WPF AccessKeyManager に対してクエリを実行するためにオーバーライドされます。 登録済みアクセラレータが見つかった場合は、AccessKeyManager によって処理されます。

  • Alt キーが押されていない場合、WPF InputManager クラスは未処理の入力を処理します。 入力がアクセラレータの場合、AccessKeyManager によって処理されます。 PostProcessInput イベントは、処理されなかったWM_CHARメッセージに対して処理されます。

ユーザーが Alt キーを押すと、アクセラレータの視覚的な手掛かりがフォーム全体に表示されます。 この動作をサポートするために、作業中のフォームのすべての ElementHost コントロールは、フォーカスがあるコントロールに関係なく、WM_SYSKEYDOWNメッセージを受信します。

メッセージは、作業中のフォームの ElementHost コントロールにのみ送信されます。

関連項目