在WinForm控件上我们可以看到很多关于键盘消息处理的方法,比如OnKeyDown, OnKeyPress, ProcessCmdKey, ProcessDialogKey,IsInputKey等等,那么这些方法是如何被组织的,每一个方法的具体含义又是什么哪?Win32的键盘消息又是如何到达控件上的这些方法的,本文将着重阐述这些问题,对.Net WinForm控件的键盘消息处理过程进行剖析。
1. WinForm消息循环
大家都知道WinForm也是依赖于底层的消息机制的,通常我们的WinForm应用程序会以如下方式启动:
Application.Run(new Form());
上面的代码将会在当前线程启动一个消息循环,并且显示指定窗体。
反编译Application类的Run方法,我们可以看到这一点:
public static void Run(Form mainForm)
{
ThreadContext.FromCurrent().RunMessageLoop(-1,new ApplicationContext(mainForm));
}
启动消息循环之后,操作系统就会将用户对于当前应用程序的UI输入转换为Windows消息发给当前线程进行处理。本文的重点不在于讲述Windows消息机制,而在于底层消息到达.Net这一层后,WinForm控件是如何处理的。
2. 消息处理
从上面可以看到通过ThreadContext类型的RunMessageLoop方法,构建了消息循环。那么对于一个特定的Windows消息,ThreadContext又是如何处理的哪?
分析ThreadContext的代码可以发现其调用关系如下:
在LocalModalMessageLoop方法中我们就可以看到对于Windows消息的处理了:
private bool LocalModalMessageLoop()
{
// ...
if(!PreTranslateMessage(ref msg))
{
// ...
UnsafeNativeMethods.TranslateMessage(ref msg);
UnsafeNativeMethods.DispatchMessage(ref msg);
}
// ...
}
可以发现对于一个特定的Windows消息,分为两个阶段进行处理:
-
PreTranslateMessage
-
DispatchMessage
WinForm控件消息的处理将从这两个地方开始。
2.1 PreTranslateMessage
PreTranslateMessage提供了一个时机,来决定是否应该Dispatch这个消息,如果返回值为False,这个消息才会派发给WinForm控件。
PreTranslateMessage分为两个层次,第一优先调用当前应用程序的IMessageFilter来进行处理,用户可以在这一层进行消息预处理或者消息过滤。如果没有被过滤掉,调用当前控件的PreProcessMessage方法进行消息预处理。
Control类型的PreProcessMessage处理流程如下:
对于WM_KeyDown消息,其预处理Control类上有三个时机:ProcessCmdKey,IsInputKey以及ProcessDialogKey;对于WM_KeyChar消息,其预处理有两个时机:IsInputChar和ProcessDialogChar。
ProcessCmdKey默认用来处理快捷键以及菜单快捷键,此方法会递归调用父控件。如果返回值为False,继续调用IsInputKey,决定是否引发KeyDown事件。如果不是InputKey,调用ProcessDialogKey来检查该键是否为导航键,或者进行一些特别的处理,此方法会递归调用父控件的处理。
IsInputChar决定输入字符是否为普通字符,如果返回值为True会引发KeyPress事件。返回值为False会调用ProcessDialogChar,ProcessDialogChar默认用来处理Mnemonic键,例如控件的文本为“&OK”, 对于Char“O”的处理。
2.2 DispatchMessage
如果PreTranslateMessage没有过滤掉该Windows消息的话,该消息将会派发到控件,交由控件的WndProc函数进行处理。
下图是控件的处理流程:
消息到达WnProc之后,会交由ProcessKeyMessage,ProcessKeyPreview以及ProcessKeyEventArgs处理。每一个方法都会返回一个Boolean值,表明控件是否已经处理了该消息。
ProcessKeyMessage会处理所有由WndProc过来的所有键消息,首先会调用父控件的ProcessKeyPreview函数,如果返回True,表明父控件已经处理。否则调用ProcessKeyEventArgs来触发控件的KeyDown,KeyPress,KeyUp事件。
3. 结语
本文着重讲述了WinForm控件对于键盘消息的处理,分析了消息预处理以及处理两个阶段的各个函数。在进行三方控件的开发中可以根据需要重载这些函数,另外也可从其设计以及实现思路中获得更多启发。
分享到:
相关推荐
DSkin是使用GDI+绘图引擎开发的.NET WinForm控件库,采用DirectUI方式绘图,绘制效率高,不闪烁,占用资源低。支持窗体和控件的任意透明效果以及动画特效。内置十多个DirectUI虚拟控件,可以自由组合嵌套。这些虚拟...
教你如何编写winform的控件,我看过了,很好
一个.net winform excel控件,用来编辑excel文件,提供了强大的excel功能,更简单应用。 支持CBScript函数式脚本,可以用excel公式进行编程。 https://dbrwe.blog.csdn.net/article/details/106436735?spm=1001.2
.net winform插件大全 .net 控件大全.net插件大全精心整理 内含教程。
c#.net winForm教程
.NET winform 集成Microsoft Word
就是皮肤控件,有60多种皮肤哦~做winform不用考虑不好看的问题了~
本资源在VS2015环境下通过自定义窗体库组合VB.NET已有控件实现DataGridView控件分页显示功能。
vb仪表盘控件,1、可以在VB6.0、VB.Net、组态王中直接作为控件调用。通过控件属性进行设置及修改仪表控件数值。给有需要的人下载
ibatis.net winform搭建带数据库,博客,http://blog.csdn.net/binyulong/article/details/78739746
SunnyUI.Net, 基于 C# .Net WinForm 开源控件库、工具类库、扩展类库、多页面开发框架
VB.NET WinForm WinSocket 客户端和服务端,代码很完善
使用方法,在VS的工具栏中,添加“选项”选择此 dll 文件,添加成功后,即会在工具栏中出现一个“HtmlEditor”,将其与其它控件一样,拖放使用即可。 要将 Microsoft.mshtml.dll 也放到软件目录中. 赋值 Me....
(.Net,VS2008SP1,C#)winform下动态生成label和控件拖动,以及控件拖动时边界的判断。
.net winform仓库管理系统源码 .net winform仓库管理系统源码 .net winform仓库管理系统源码
C# .NET Winform 仿QQ自动隐藏控件(使用简单),就把里面的属性设为本窗体就可以了
Qios DevSuite is an advanced .NET control library, that is fully integrated with Visual Studio.NET and can be used with all .NET languages, such as C#, VB.NET and C++.NET. Qios DevSuite is a FREE ...
1、自己绘制菜单 2、想窗体的系统菜单添加菜单项 3、无标题窗体的拖动 4、设置应用程序的图标 5、共享菜单项 6、动态设置窗体的光标
net分页控件,为datagridview绑定添加一个分页控件,带源码,一键式傻瓜调用。基于net2.0开发,源码带注释,适合学习商用
FLASH控件,.net flash控件,winform flash播放控件, vs.net flash播放控件