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

更新 : 2007 年 11 月

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

このトピックは、次の内容で構成されています。

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

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

  • ElementHost のキーボードおよびメッセージ処理

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

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

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

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

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

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

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

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

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

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

Windows Presentation Foundation メッセージ ループからのメッセージの取得

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

相互運用性の実装は ComponentDispatcher.ThreadFilterMessage イベントを処理し、Windows フォーム コントロールが、WPF コントロールよりも前にメッセージを処理できるようにします。

サロゲート 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 フォーム コントロールへの Tab キーによる移動はできなくなります。

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

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

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

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

WindowsFormsHost の登録

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

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

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

ElementHost のキーボードおよびメッセージ処理

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

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

  • Tab キーと方向キー。

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

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

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

インターフェイスの実装

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

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

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

Tab キーと方向キー

Tab キーおよび方向キーによる移動を実装するために、Windows フォームの選択ロジックは IKeyboardInputSink.TabInto メソッドと OnNoMoreTabStops メソッドにマッピングされます。Select メソッドをオーバーライドして、このマッピングを実現します。

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

WPF に対して、コマンド キーとダイアログ キーを処理する最初の機会を提供するために、Windows フォーム コマンドの事前処理が TranslateAccelerator メソッドに関連付けられます。Control.ProcessCmdKey メソッドをオーバーライドすると、2 つのテクノロジが関連付けられます。

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

アクセラレータ処理

アクセラレータを正しく処理するには、Windows フォーム アクセラレータ処理を WPFAccessKeyManager クラスに関連付ける必要があります。また、すべての WM_CHAR メッセージは、ホストされている要素に正しくルーティングされる必要があります。

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

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

  • Alt キーが押された場合、メッセージは WM_SYSCHAR になります。Windows フォームは、このメッセージを IsInputChar メソッドを通して事前に処理しません。したがって、ProcessMnemonic メソッドは、登録済みのアクセラレータを WPFAccessKeyManager に照会するためにオーバーライドされます。登録済みのアクセラレータが見つかった場合、AccessKeyManager はそのアクセラレータを処理します。

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

ユーザーが Alt キーを押すと、アクセラレータのビジュアル キューがフォーム全体に示されます。この動作をサポートするために、アクティブ フォーム上のすべての ElementHost コントロールは、フォーカスがどのコントロールに設定されているかに関係なく、WM_SYSKEYDOWN メッセージを受け取ります。

メッセージは、アクティブ フォーム内の ElementHost コントロールにだけ送信されます。

参照

概念

チュートリアル : Windows Presentation Foundation での Windows フォーム複合コントロールのホスト

チュートリアル : Windows フォームでの Windows Presentation Foundation コントロールのホスト

WPF と Win32 の相互運用性に関する概要

参照

EnableWindowsFormsInterop

EnableModelessKeyboardInterop

ElementHost

WindowsFormsHost