使用 Managed 視窗程序將控制項子類別化

更新:2007 年 11 月

.NET Compact Framework 可讓機器碼使用回呼 (Callback) 委派 (Delegate) 呼叫 Managed 程式碼。透過子類別化 (Subclass) Managed 控制項以接收從對應原生控制項的回呼,您就可以建立具備 .NET Compact Framework 中無法直接使用功能的控制項。

對於瞭解 Windows 程式設計和控制項子類別化的程式設計人員而言,這是進階的主題。若要子類別化控制項,您將會需要瞭解原生控制項的內部詳細資料,以及它如何對應至您想要在 Managed 控制項之擴充中提供的功能。您將會需要瞭解要監視哪些 Windows 訊息,以及要叫用 (Invoke) 哪些原生 Windows Embedded CE 函式以提供所需功能。

這個主題將會說明如何子類別化 TreeViewButton 控制項,而下列主題則會提供建置應用程式的程式碼範例和指示。

HOW TO 主題

說明

HOW TO:使用原生回呼子類別化樹狀檢視控制項

子類別化 TreeView 控制項以建立 NodeMouseClick 事件的實作。.NET Compact Framework 並無法直接支援這個方法,因為必須要限制有限資源的大小。

HOW TO:使用原生回呼子類別化按鈕控制項

子類別化 Button 控制項以顯示色彩豐富的漸層填滿。

請注意,提供這個按鈕主要是要示範如何使用子類別化和回呼。如需建立漸層填滿之按鈕的簡易方式,請參閱 HOW TO:顯示漸層填滿

這些子類別化程式都含有原生 Win32 結構的 WndProcHooker 類別和 Helper 類別、平台叫用宣告,以及 WndProc 委派。如需程式碼清單,請參閱 HOW TO:使用用來攔截 Windows 程序的類別HOW TO:使用 Helper 類別進行平台叫用

WndProcHooker 類別

收到原生控制項的特定 Windows 訊息時,WndProcHooker 類別就可讓該控制項 (或視窗) 叫用 Managed 程式碼的回呼。您可以將原生控制項的視窗程序 (WndProc) 取代成泛型視窗程序 WindowProc 以達成此目的,而且該程序會執行查閱,以判斷控制項是否位於要叫用之回呼方法相關的控制項清單中。如果是的話,該控制項就會視為即將要攔截 (Hook)。

如果控制項已攔截,WindowProc 就會判斷控制項是否對應至回應特定 Windows 訊息。這就是訊息對應 (Message Map),它會將 Windows 訊息與呼叫含有所需功能之 Managed 方法的 WndProcCallback 委派相對應。如果訊息對應含有訊息,則 WndProcCallback 委派就會使用提供給 WindowProc 的訊息參數,叫用程式碼。

攔截控制項

HookWndProc 方法會將控制項的控制代碼與泛型視窗程序 WindowProc 將要使用的訊息對應產生關聯。這就稱為攔截控制項。

HookWndProc 方法會判斷控制項是否已經被攔截。如果沒有,它就會為該控制項建立 HookedProcInformation 物件。這個物件含有控制項和訊息對應的參考。如果已經建立控制項的控制代碼,它就會攔截視窗,方法是建立視窗之原始視窗程序的指標,以供日後還原使用。如果尚未建立控制代碼,它就會被處理 HandleCreated 事件的 ctrl_HandleCreated 方法所攔截。

然後,HookWndProc 方法就會將 HookedProcInformation 物件加入至其中一個泛型字典集合:

  • hwindDict 字典,其中包含所有已攔截視窗控制代碼的全域清單。索引鍵是 hwnd。已經建立控制代碼的控制項都會進入這個字典。這個字典中的控制項會由任何對應訊息的 WindowProc 進行評估。

  • ctlDict 字典,其中包含未建立控制代碼的控制項。呼叫 ctrl_HandleCreated 方法時,控制項會移到 hwndDict 字典中。

取消攔截控制項

UnhookWndProc 方法會提供兩種取消攔截控制項的方式:

  • 從控制項的訊息對應移除訊息,但仍然將控制項保留在已攔截視窗的 hwndDict 字典中。此外,這個方法也會使用 HookedProcInformation 物件中保存的指標,還原控制項的原始視窗程序。

  • 從已攔截控制項的 hwndDict 字典移除控制項,然後移除其控制代碼並放置在 ctrlDict 字典中,或是處置整個控制項。此外,這個方法也會使用 HookedProcInformation 物件中保存的控制代碼,還原控制項的原始視窗程序。

子類別化 TreeView 控制項

此範例程式 TreeViewBonus 類別 (列於 HOW TO:使用原生回呼子類別化樹狀檢視控制項中) 會擴充 TreeView 控制項,以便加入無法直接在 .NET Compact Framework 中使用的 NodeMouseClick 事件。

NodeMouseClick 事件的取得方式是將 WM_NOTIFY 訊息加入至控制項的訊息對應,如同 WndProcHooker 類別的執行方式一樣。Managed 回呼方法 WM_Notify_Handler 會叫用原生 GetMessagePos 函式,以取得傳送 Windows 訊息時,滑鼠游標的座標。

請注意,這些座標是相對於螢幕的可見工作區 (Client Area),而非相對於 TreeView 控制項。TreeViewBonus 類別會使用控制項的 PointToClient 方法,將螢幕座標轉換成用戶端座標。然後,就會將這些用戶端座標與 TVM_HITTEST 訊息一併傳送,以判斷是否按下 TreeViewBonus 物件以及按下的位置。

TreeViewBonus 類別含有一些程式碼,可使用原生控制項的 TVM_HITTEST 訊息,取得相對於控制項的座標。

如果點選動作發生在其中一個樹狀檢視節點上,原生 TVHITTESTINFO 結構就會包含該節點的控制代碼。最後一個步驟是由 FindTreeNodeFromHandle 方法,遞迴地周遊的 Managed TreeView 節點,以便找出相符的控制代碼並引發 NodeMouseClick 事件。TreeNodeMouseClickEventArgs 類別可提供下列資料:

  • 已按下的節點

  • 已按下的按鈕。

  • 按下的次數,設定為 1

  • 發生點選動作的 X 座標

  • 發生點選動作的 Y 座標

TreeViewBonus 類別會攔截 Managed 視窗程序之原生樹狀檢視控制項的父代,如同 WndProcHooker 類別的執行方式一樣。然後,它會攔截父控制項,藉以回應 OnParentChanged 事件,進而提供 TreeView 已移至新父代的可能性,例如從 Form 移至 Panel

子類別化按鈕控制項

GradientFilledButton 和 GradientFill 類別 (列於 HOW TO:使用原生回呼子類別化按鈕控制項中) 會擴充 Button 控制項,以便顯示介於兩個色彩之間的漸層填滿。這個程式主要是用來示範子類別化。不過,在按鈕中顯示漸層填滿較簡單的方式是,建立從 Control 衍生的自訂控制項,如 HOW TO:顯示漸層填滿所述。

GradientFilledButton 類別的建構函式會建立 WndProcHooker 類別的執行個體,以便將 Windows 訊息對應至 Managed 回呼。這些回呼方法會根據 Windows 訊息和控制項的 Capture 屬性狀態,以適當的狀態繪製按鈕。下表將列出對應的 Windows 訊息及其對應回呼。

Windows 訊息

Managed 回呼方法和說明

WM_KEYDOWN

WM_KeyDown_Handler - 如果 SPACEBAR 或 ENTER (或動作) 鍵已按下,便以壓下的狀態重繪按鈕。

WM_KEYUP

WM_KeyUp_Handler - 以未壓下的狀態重繪按鈕,但如果按下的按鍵是 SPACEBAR 或 ENTER (動作) 鍵,便引發 Click 事件。

WM_LBUTTONDOWN

WM_LeftButtonDown_Hander - 以壓下的狀態重繪按鈕,並將控制項的滑鼠 Capture 屬性設定為 true。

WM_LBUTTONUP

WM_LButtonUp_Handler - 以未壓下的狀態重繪按鈕、如果游標是在控制項的工作區內放開便引發 MouseUp 事件,並將控制項的滑鼠 Capture 屬性設定為 false。

WM_MOUSEMOVE

WM_MouseMove_Handler - 如果之前已按下按鈕且 Capture 為 true,便重繪按鈕。

WM_PAINT

WM_Paint_Handler - 以適當的狀態重繪按鈕。

這些 Managed 回呼方法會使用 DrawButton 方法,以適當的狀態繪製按鈕。這個方法含有兩個多載,可在視窗 (本範例所使用) 或 Graphics 物件上繪製按鈕。如果按鈕已按下,則這兩個多載都會採用 true 的布林值 (Boolean)。

GradientFilledButton 類別會使用 GradientFill 類別,執行機器碼的平台叫用呼叫以進行填滿。此外,GradientFill 類別會提供一些屬性,以便設定開始和結束色彩,以及將填滿方向指定為由左至右或由上至下。

請參閱

工作

HOW TO:使用用來攔截 Windows 程序的類別

HOW TO:使用 Helper 類別進行平台叫用

HOW TO:使用原生回呼子類別化樹狀檢視控制項

HOW TO:顯示漸層填滿

概念

.NET Compact Framework HOW TO 主題

其他資源

.NET Compact Framework 中的互通性