WPF フォームと Windows フォーム間の相互運用には、両方のテクノロジに適切なキーボード入力処理が必要です。 このトピックでは、ハイブリッド アプリケーションでの円滑な相互運用を可能にするために、これらのテクノロジでキーボードとメッセージ処理を実装する方法について説明します。
このトピックには、次のサブセクションが含まれています。
モードレス フォームとダイアログ ボックス
WindowsFormsHost キーボードとメッセージ処理
ElementHost キーボードとメッセージ処理
モードレス フォームとダイアログ ボックス
EnableWindowsFormsInterop要素のWindowsFormsHost メソッドを呼び出して、WPF ベースのアプリケーションからモードレス フォームまたはダイアログ ボックスを開きます。
EnableModelessKeyboardInterop コントロールで ElementHost メソッドを呼び出して、Windows フォーム ベースのアプリケーションでモードレス WPF ページを開きます。
WindowsFormsHost キーボードとメッセージ処理
WPF ベースのアプリケーションによってホストされている場合、Windows フォームのキーボードとメッセージの処理は次の要素で構成されます。
WindowsFormsHost クラスは、 クラスによって実装される WPF メッセージ ループからメッセージを取得します。
WindowsFormsHost クラスは、Windows フォームの通常のキーボード処理が確実に行われるように、代理 Windows フォーム メッセージ ループを作成します。
WindowsFormsHost クラスは、WPF とフォーカス管理を調整するIKeyboardInputSink インターフェイスを実装します。
WindowsFormsHost コントロールは自身を登録し、メッセージ ループを開始します。
以降のセクションでは、プロセスのこれらの部分について詳しく説明します。
WPF メッセージ ループからのメッセージの取得
ComponentDispatcher クラスは、WPF のメッセージ ループ マネージャーを実装します。 ComponentDispatcher クラスは、WPF がメッセージを処理する前に外部クライアントがメッセージをフィルター処理できるようにするフックを提供します。
相互運用の実装は、 ComponentDispatcher.ThreadFilterMessage イベントを処理します。これにより、Windows フォーム コントロールは WPF コントロールの前にメッセージを処理できます。
サロゲート Windows フォーム メッセージ ループ
既定では、 System.Windows.Forms.Application クラスには、Windows フォーム アプリケーションのプライマリ メッセージ ループが含まれています。 相互運用中、Windows フォーム メッセージ ループはメッセージを処理しません。 したがって、このロジックを再現する必要があります。 ComponentDispatcher.ThreadFilterMessage イベントのハンドラーは、次の手順を実行します。
IMessageFilter インターフェイスを使用してメッセージをフィルター処理します。
Control.PreProcessMessage メソッドを呼び出します。
必要に応じて、メッセージを翻訳してディスパッチします。
他のコントロールがメッセージを処理しない場合は、メッセージをホスティング コントロールに渡します。
IKeyboardInputSink の実装
サロゲート メッセージ ループは、キーボード管理を処理します。 したがって、IKeyboardInputSink.TabInto メソッドは、IKeyboardInputSink クラスでの実装を必要とする唯一のWindowsFormsHostメンバーです。
既定では、HwndHost クラスはfalse
実装のIKeyboardInputSink.TabIntoを返します。 これにより、WPF コントロールから Windows フォーム コントロールへのタブ移動が禁止されます。
WindowsFormsHost メソッドのIKeyboardInputSink.TabInto実装では、次の手順を実行します。
WindowsFormsHost コントロールに含まれており、フォーカスを受け取ることができる最初または最後の Windows フォーム コントロールを検索します。 コントロールの選択はトラバーサル情報によって異なります。
コントロールにフォーカスを設定し、
true
を返します。フォーカスを受け取ることができるコントロールがない場合は、
false
を返します。
WindowsFormsHost 登録
WindowsFormsHost コントロールへのウィンドウ ハンドルが作成されると、WindowsFormsHost コントロールは、メッセージ ループの存在を登録する内部静的メソッドを呼び出します。
登録中、 WindowsFormsHost コントロールはメッセージ ループを調べます。 メッセージ ループが開始されていない場合は、 ComponentDispatcher.ThreadFilterMessage イベント ハンドラーが作成されます。 メッセージ ループは、 ComponentDispatcher.ThreadFilterMessage イベント ハンドラーがアタッチされたときに実行されていると見なされます。
ウィンドウ ハンドルが破棄されると、 WindowsFormsHost コントロールは登録から自身を削除します。
ElementHost キーボードとメッセージ処理
Windows フォーム アプリケーションによってホストされている場合、WPF キーボードとメッセージ処理は次の要素で構成されます。
HwndSource、 IKeyboardInputSink、および IKeyboardInputSite インターフェイスの実装。
タブキーと方向キー。
コマンド キーとダイアログ ボックス キー。
Windows フォーム アクセラレータの処理。
以降のセクションでは、これらの部分について詳しく説明します。
インターフェイスの実装
Windows フォームでは、キーボード メッセージはフォーカスのあるコントロールのウィンドウ ハンドルにルーティングされます。 ElementHost コントロールでは、これらのメッセージはホストされる要素にルーティングされます。 これを実現するために、 ElementHost コントロールは HwndSource インスタンスを提供します。 ElementHost コントロールにフォーカスがある場合、HwndSource インスタンスはほとんどのキーボード入力をルーティングして、WPF InputManager クラスで処理できるようにします。
HwndSource クラスは、IKeyboardInputSinkインターフェイスとIKeyboardInputSite インターフェイスを実装します。
キーボード相互運用は、tab キーと方向キーの入力を処理する OnNoMoreTabStops メソッドを実装し、ホストされている要素からフォーカスを移動することに依存します。
タブキーと矢印キー
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メッセージをホストされる要素に正しくルーティングする必要があります。
HwndSource メソッドの既定のTranslateChar実装では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 コントロールにのみ送信されます。
こちらも参照ください
.NET Desktop feedback