一直想整理键盘事件的调用顺序,刚好看见园子里的这篇文章,写的不错,就转载了:http://www.cnblogs.com/tedzhao/archive/2010/09/07/1820557.html

在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控件对于键盘消息的处理,分析了消息预处理以及处理两个阶段的各个函数。在进行三方控件的开发中可以根据需要重载这些函数,另外也可从其设计以及实现思路中获得更多启发。

WinForm 控件键盘消息处理剖析(转)的更多相关文章

  1. .Net WinForm 控件键盘消息处理剖析

    在WinForm控件上我们可以看到很多关于键盘消息处理的方法,比如OnKeyDown, OnKeyPress, ProcessCmdKey, ProcessDialogKey,IsInputKey等等 ...

  2. 通过WinForm控件创建的WPF控件无法输入的问题

    今天把写的一个WPF程序发布到别的机器上执行,发现一个比较奇怪的问题:在那个机器上用英文输入法无法输入数字,非要切换到中文输入法才行:但在我的机器上却是好好的. 最开始以为是输入法的问题,弄了好一阵子 ...

  3. 通过C# WinForm控件创建的WPF WIndow窗口控件无法输入的问题

    原文:通过WinForm控件创建的WPF 控件无法输入的问题 今天把写的一个WPF程序发布到别的机器上执行,发现一个比较奇怪的问题:在那个机器上用英文输入法无法输入数字,非要切换到中文输入法才行:但在 ...

  4. 在WPF中使用WinForm控件方法

    1.      首先添加对如下两个dll文件的引用:WindowsFormsIntegration.dll,System.Windows.Forms.dll. 2.      在要使用WinForm控 ...

  5. WPF 调用WinForm控件

    WPF可以使用WindowsFormsHost控件做为容器去显示WinForm控件,类似的用法网上到处都是,就是拖一个WindowsFormsHost控件winHost1到WPF页面上,让后设置win ...

  6. WinForm控件TreeView 只部分节点显示 CheckBox

    WinForm控件TreeView 只部分节点显示  CheckBox 用过asp.net的应该知道,要在treeview中实现上述功能可以使用ShowCheckBox 属性指定那些节点显示check ...

  7. Winform控件重写

    Winform控件重写 因为最近的项目中越来越多的遇到了比较特殊的一些控件,有时候我们自己封装一下可能更加方便我们的使用,下面是我们项目中用到的,简单做一个记录. TextBox控件重写 主要的控制代 ...

  8. MFC编程入门之九(对话框:为控件添加消息处理函数)

    这一节讲的主要内容是如何为控件添加消息处理函数. MFC为对话框和控件定义了诸多消息,我们对他们操作时会触发消息,这些消息最终由消息处理函数处理,比如我们点击按钮时就会产生BN_CLICKED消息,修 ...

  9. c#Winform控件总结

    1. C# WinForm控件.自定义控件整理(大全) (http://www.cnblogs.com/top5/archive/2010/04/29/1724039.html) 2. c#窗体控件用 ...

随机推荐

  1. 最全PyCharm教程

    最全PyCharm教程--for python PyCharm简介: PyCharm是由JetBrains打造的一款Python IDE,VS2010的重构插件Resharper就是出自JetBrai ...

  2. 使用C#和Thrift来访问Hbase实例

    今天试着用C#和Thrift来访问Hbase,主要参考了博客园上的这篇文章.查了Thrift,Hbase的资料,结合博客园的这篇文章,终于搞好了.期间经历了不少弯路,下面我尽量详细的记录下来,免得大家 ...

  3. SpringBoot+mybatis实现多数据源支持

    什么是多数据源支持? 简单的说,就是一个项目里,同时可以访问多个不同的数据库. 实现原理 单个数据源在配置时会绑定一套mybatis配置,多个数据源时,不同的数据源绑定不同的mybatis配置就可以了 ...

  4. SQL Server 2008 添加登录账户 配置权限

    首先打开数据库,并以windows身份验证模式扥牢固数据库, 然后在左侧的[对象资源管理器中]展开[安全性]节点,鼠标右键点击节点中的[登录名],在弹出的菜单中单击[新建登录名],弹出如图对话框: 然 ...

  5. 腾讯云服务器 离线安装最新稳定版MariaDB 10.2.6

    数据库方面我们一般都是使用mysql,由于前段时间我们切换到了MariaDB后,当然生产环境也要更着变,谁叫oracle是个碧池呢! mariaDB主要有三种安装方式 源码安装,有点繁琐,不推荐 yu ...

  6. asp.net 中用easyui中的treegird的简单使用

    几乎每个‘数人头’项目中都会用到的功能,这里先记下来,以后直接到这里复制代码就行了,ASP.NET MVC中的使用 数据库用户表中的除了有个parentid父级ID外,我还多加了以个字段,parent ...

  7. Atitti 过程导向 vs 结果导向 attlax的策

    Atitti 过程导向 vs 结果导向 attilax的策略 1. 结果导向的问题 以结果为导向”的明显弊端2 1.1. 白猫黑猫的策略是错误的2 1.2. 为了目的不择手段,完全违背了程序正义原则2 ...

  8. Windows 虚拟桌面工具 Desktops v2.0

    https://technet.microsoft.com/en-us/sysinternals/cc817881.aspx

  9. password学4——Java 加密解密之消息摘要算法(MD5 SHA MAC)

    Java 加密解密之消息摘要算法(MD5 SHA MAC) 消息摘要 消息摘要(Message Digest)又称为数字摘要(Digital Digest). 它是一个唯一相应一个消息或文本的固定长度 ...

  10. iOS按钮的基本使用代码优化

    将图片按钮进行连线, 声明方法同时连接六个按钮 -(void)move:(UIButton *)btn{ //    NSLog(@"看见一个美女"); //头尾式动画 //0.开 ...