使用托管窗口过程设置控件的子类

更新:2007 年 11 月

.NET Compact Framework 为本机代码提供了使用回调委托来调用托管代码的功能。设置托管控件的子类以从对应的本机控件接收回调,便可以创建具有 .NET Compact Framework 未直接提供的功能的控件。

本高级主题面向通晓 Windows 编程和控件子类设置的开发人员。若要设置控件的子类,您需要了解本机控件的内部细节,需要了解本机控件如何映射到要在托管控件的扩展中提供的功能。此外,您还需要了解应对哪些 Windows 消息进行监视,应调用哪些本机 Windows Embedded CE 函数以提供所需的功能。

本主题说明如何设置 TreeViewButton 控件的子类,后面的主题提供生成应用程序的代码示例和说明。

帮助主题

演示

如何:使用本机回调创建 TreeView 的子类

设置 TreeView 控件的子类,以创建 NodeMouseClick 事件的实现。.NET Compact Framework 受资源约束需要限制自身大小,因此它不直接支持此方法。

如何:使用本机回调创建 Button 的子类

设置 Button 控件的子类,以显示彩色的渐变填充。

注意,提供此按钮主要是为了演示如何使用子类设置和回调。有关创建渐变填充按钮的简易方法,请参见如何:显示渐变填充

以上两个子类设置程序均包括 WndProcHooker 类和本机 Win32 结构的帮助器类、平台调用声明以及 WndProc 委托。有关代码清单,请参见如何:使用类来挂钩 Windows 过程如何:将帮助器类用于平台调用

WndProcHooker 类

WndProcHooker 类提供以下功能:当收到针对某个本机控件(即窗口)的特定 Windows 消息时,让该控件调用对托管代码的回调。此功能通过将本机控件的窗口过程 (WndProc) 替换为通用窗口过程 WindowProc 来实现,该通用窗口过程执行查找,以确定该控件是否在与调用的回调方法关联的控件列表中。如果是,则该控件被视为挂钩的。

如果该控件是挂钩的,则 WindowProc 确定是否映射该控件以响应特定的 Windows 消息。这就是消息映射,它将 Windows 消息与 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 控件的子类

如何:使用本机回调创建 TreeView 的子类中列出的示例程序 TreeViewBonus 类扩展了 TreeView 控件,以包含 NodeMouseClick 事件,.NET Compact Framework 中没有直接提供该事件。

NodeMouseClick 事件是通过将 WM_NOTIFY 消息添加到控件的消息映射获得的,如 WndProcHooker 类所执行的那样。托管的回调方法 WM_Notify_Handler 调用 GetMessagePos 本机函数以获取发送 Windows 消息时的鼠标光标的坐标。

注意,这些坐标相对于屏幕的可见工作区,而不是相对于 TreeView 控件。TreeViewBonus 类通过控件的 PointToClient 方法将屏幕坐标转换为客户端坐标。然后,这些客户端坐标随同 TVM_HITTEST 消息一起发送,以确定是否单击了 TreeViewBonus 对象以及在何处单击了该对象。

TreeViewBonus 类包含一些代码,这些代码使用本机控件的 TVM_HITTEST 消息获取相对于控件的坐标。

如果单击发生在某个树视图节点上,则 TVHITTESTINFO 本机结构包含该节点的句柄。最后一步是递归地遍历托管的 TreeView 节点(由 FindTreeNodeFromHandle 方法执行)以查找匹配的句柄并引发 NodeMouseClick 事件。TreeNodeMouseClickEventArgs 类提供了以下数据:

  • 被单击的节点。

  • 单击的按钮。

  • 单击次数,设置为 1。

  • 单击发生处的 x 坐标。

  • 单击发生处的 y 坐标。

TreeViewBonus 类将本机树视图控件的父级挂钩到一个托管窗口过程,如 WndProcHooker 类执行的那样。该类通过挂钩父控件并由此提供将 TreeView 移至新父级的可能性(例如从 Form 移入 Panel)来响应 OnParentChanged 事件。

设置 Button 控件的子类

如何:使用本机回调创建 Button 的子类中列出的 GradientFilledButton 和 GradientFill 类扩展了 Button 控件以显示两种颜色之间的渐变填充。此程序主要演示如何设置子类。但是,在按钮中显示渐变填充的更简单的方法是创建派生自 Control 的自定义控件,如如何:显示渐变填充中所述。

GradientFilledButton 类的构造函数创建 WndProcHooker 类的实例以将 Windows 消息映射到托管回调。这些回调方法根据 Windows 消息以及控件的 Capture 属性的状态以适当的状态绘制按钮。下表列出了映射的 Windows 消息及其对应的回调。

Windows 消息

托管回调方法和说明

WM_KEYDOWN

WM_KeyDown_Handler -- 如果按下了空格键或 Enter(或 Action)键则以按下的状态重新绘制按钮。

WM_KEYUP

WM_KeyUp_Handler -- 如果按下的键是空格键或 Enter (Action) 键,则以未按下的状态重新绘制按钮并引发 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 -- 以适当的状态重新绘制按钮。

这些托管回调方法使用 DrawButton 方法以适当的状态绘制按钮。此方法有两种重载,一种用于在窗口上绘制按钮(此示例使用该重载),另一种在 Graphics 对象上绘制。如果按钮被按下,则两种重载都接受值为 true 的布尔值。

GradientFilledButton 类使用 GradientFill 类执行平台调用,调用执行填充的本机代码。GradientFill 类提供设置起始和结束颜色的属性,并提供将填充方向设置为从左至右或从上至下的属性。

请参见

任务

如何:使用类来挂钩 Windows 过程

如何:将帮助器类用于平台调用

如何:使用本机回调创建 TreeView 的子类

如何:显示渐变填充

概念

.NET Compact Framework 帮助主题

其他资源

.NET Compact Framework 中的互操作性