Windows Form 和 WPF 互通性輸入架構
WPF 與 Windows Forms 之間的互操作需要這兩種技術都有適當的鍵盤輸入處理。 本主題描述這些技術如何實作鍵盤和訊息處理,以在混合式應用程式中啟用平滑的互操作。
本主題包含下列子章節:
非強制回應表單和對話方塊
WindowsFormsHost 鍵盤和訊息處理
ElementHost 鍵盤和訊息處理
非強制回應表單和對話方塊
在 WindowsFormsHost 元素上呼叫 EnableWindowsFormsInterop 方法,以從 WPF 型應用程式開啟非強制回應表單或對話方塊。
在 ElementHost 控制項上呼叫 EnableModelessKeyboardInterop 方法,以在 Windows Forms 型應用程式中開啟非強制回應 WPF 頁面。
WindowsFormsHost 鍵盤和訊息處理
以 WPF 型應用程式裝載時,Windows Forms 鍵盤和訊息處理包含下列項目:
WindowsFormsHost 類別會從 WPF 訊息迴圈取得訊息,而 WPF 訊息迴圈是由 ComponentDispatcher 類別實作。
WindowsFormsHost 類別會建立 Surrogate Windows Forms 訊息迴圈,以確保會發生一般 Windows Forms 鍵盤處理。
WindowsFormsHost 類別會實作 IKeyboardInputSink 介面,以協調 WPF 的焦點管理。
WindowsFormsHost 控制項會自行註冊並啟動其訊息迴圈。
下列各節將更詳細說明流程的這些部分。
從 WPF 訊息迴圈取得訊息
ComponentDispatcher 類別會實作 WPF 的訊息迴圈管理員。 ComponentDispatcher 類別提供勾點,讓外部用戶端在 WPF 處理訊息之前篩選訊息。
互操作實作會處理 ComponentDispatcher.ThreadFilterMessage 事件,這可讓 Windows Forms 控制項在 WPF 控制項之前處理訊息。
Surrogate Windows Forms 訊息迴圈
根據預設,System.Windows.Forms.Application 類別包含 Windows Forms 應用程式的主要訊息迴圈。 在互操作期間,Windows Forms 訊息迴圈不會處理訊息。 因此,必須重現此邏輯。 ComponentDispatcher.ThreadFilterMessage 事件的處理程式會執行下列步驟:
使用 IMessageFilter 介面篩選訊息。
呼叫 Control.PreProcessMessage 方法。
如果需要,翻譯並分派訊息。
如果沒有其他控制項處理訊息,則將訊息傳遞至裝載控制項。
IKeyboardInputSink 實作
Surrogate 訊息迴圈會處理鍵盤管理。 因此,IKeyboardInputSink.TabInto 方法是唯一需要 WindowsFormsHost 類別中實作的 IKeyboardInputSink 成員。
根據預設,HwndHost 類別會傳回其 IKeyboardInputSink.TabInto 實作的 false
。 這可防止從 WPF 控制項移至 Windows Forms 控制項的定位處理。
IKeyboardInputSink.TabInto 方法的 WindowsFormsHost 實作會執行下列步驟:
尋找 WindowsFormsHost 控制項所包含的第一個或最後一個 Windows Forms 控制項,而且可以接收焦點。 控制項選擇取決於周遊資訊。
將焦點設定為控制項,並傳回
true
。如果沒有控制項可以接收焦點,則會傳回
false
。
WindowsFormsHost 註冊
建立至 WindowsFormsHost 控制項的視窗控制代碼時,WindowsFormsHost 控制項會呼叫內部靜態方法,以註冊其訊息迴圈的存在。
在註冊期間,WindowsFormsHost 控制項會檢查訊息迴圈。 如果訊息迴圈尚未啟動,則會建立 ComponentDispatcher.ThreadFilterMessage 事件處理程式。 附加 ComponentDispatcher.ThreadFilterMessage 事件處理程式時,訊息迴圈會被視為正在執行。
當視窗控制代碼終結時,WindowsFormsHost 控制項會從註冊中移除其本身。
ElementHost 鍵盤和訊息處理
由 Windows Forms 應用程式裝載時,WPF 鍵盤和訊息處理包含下列項目:
定位處理和方向鍵。
命令索引鍵和對話方塊索引鍵。
Windows Forms 加速器處理。
下列各節會更詳細地說明這些部分。
介面實作
在 Windows Forms 中,鍵盤訊息會路由傳送至具有焦點之控制項的視窗控制代碼。 在 ElementHost 控制項中,這些訊息會路由傳送至裝載元素。 若要達成此目的,ElementHost 控制項會提供 HwndSource 實例。 如果 ElementHost 控制項有焦點,HwndSource 實例會路由傳送大部分的鍵盤輸入,以便 WPF InputManager 類別處理它。
HwndSource 類別會實作 IKeyboardInputSink 和 IKeyboardInputSite 介面。
鍵盤互操作依賴實作 OnNoMoreTabStops 方法來處理 TAB 鍵和方向鍵輸入,以將焦點移出裝載元素。
定位處理和方向鍵
Windows Forms 選取邏輯會對應至 IKeyboardInputSink.TabInto 及 OnNoMoreTabStops 方法來實作 TAB 和方向鍵瀏覽。 覆寫 Select 方法會完成此對應。
命令索引鍵和對話方塊索引鍵
為了讓 WPF 第一次有機會處理命令索引鍵和對話方塊索引鍵,Windows Forms 命令前置處理會連線到 TranslateAccelerator 方法。 覆寫 Control.ProcessCmdKey 方法會連接這兩種技術。
使用 TranslateAccelerator 方法,裝載元素可以處理任何索引鍵訊息,例如 WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN 或WM_SYSKEYUP,包括 TAB、ENTER、ESC 和方向鍵。 如果未處理索引鍵訊息,則會向上傳送至 Windows Forms 上階階層進行處理。
加速器處理
若要正確處理加速器,Windows Forms 加速器處理必須連線到 WPF AccessKeyManager 類別。 此外,所有 WM_CHAR 訊息都必須正確路由傳送至裝載元素。
由於 TranslateChar 方法的預設 HwndSource 實作會傳回 false
,因此會使用下列邏輯來處理 WM_CHAR 訊息:
系統會覆寫 Control.IsInputChar 方法,以確保所有 WM_CHAR 訊息都會轉送至裝載元素。
如果按下 ALT 鍵,該訊息是 WM_SYSCHAR。 Windows Forms 不會透過 IsInputChar 方法對此訊息進行前置處理。 因此,會覆寫 ProcessMnemonic 方法來查詢已註冊加速器的 WPF AccessKeyManager。 如果找到已註冊的加速器,AccessKeyManager 會處理它。
如果未按下 ALT 鍵,WPF InputManager 類別會處理未處理的輸入。 如果輸入是加速鍵,則 AccessKeyManager 會處理它。 PostProcessInput 事件是針對未處理的 WM_CHAR 訊息進行處理。
當使用者按下 ALT 鍵時,整個表單上會顯示加速器視覺效果提示。 為了支援此行為,不論哪個控制項具有焦點,使用中表單上的所有 ElementHost 控制項都會接收 WM_SYSKEYDOWN 訊息。
訊息只會傳送至使用中表單上的 ElementHost 控制項。