WinForm事件与消息
WinForm事件与消息
消息概述以及在C#下的封装
Windows下应用程序的执行是通过消息驱动的。所有的外部事件,如键盘输入、鼠标移动、按动鼠标都由OS系统转换成相应的“消息”,进入到应用程序的消息队列中,由应用程序引擎轮询处理。在C#中,消息被应用程序的工作引擎通过轮询等方式遍历获取并按照消息的类型逐个分发到对应的组件(例如窗体、按钮等),最后调用对应组件所注册的事件进行处理。
在.NET框架类库中的System.Windows.Forms命名空间中微软采用面对对象的方式重新定义了Message。该消息主要有一下的几个公共属性:
System.Windows.Forms.Message
HWnd 获取或设定消息的处理函数
Msg 获取或设定消息的ID号
Lparam 指定消息的LParam字段
Wparam 指定消息的WParam字段
Result 指定为响应消息处理函数而向OS系统返回的值
System.Windows.Forms.Application
System.Windows.Forms.Application类具有用于启动和停止应用程序和线程以及处理Windows消息的方法。例如,调用Run以启动当前线程上的应用程序消息循环,并可以选择使其窗体可见;调用Exit或ExitThread来停止消息循环。所以我们经常使用vs初始化一个基本的WinForm程序,显示的下列模板代码:
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); // 调用Run以启动当前线程上的应用程序消息循环
}
因为Application是在单线程中运行的,所以在Application.Run开始后,Application本身不断轮询检查消息队列,然后根据消息类型进行数据分发。例如,当我们为这个Form1增加一个鼠标的点击事件后,我们运行该打开Form1:
Form1 form1 = new Form1();
form1.MouseClick += (sender, e) => MessageBox.Show("1");
form1.MouseClick += (sender, e) => MessageBox.Show("2");
Application.Run(form1);
运行后点击Form,可以看到首先出现一个MessageBox,展示“1”,我们点击确定后,又会出现MessageBox,展示“2”。实际上整个过程应该如下:
当我们按下鼠标左键后,消息形成并送往应用程序消息队列中,然后被Application类从应用程序消息队列中取出,然后分发到相应的窗体。窗体使用MouseClick事件中的函数指针调用已经添加的响应函数。所以C#中的事件字段实质上是一个函数指针列表,用来维护一些消息到达时的响应函数的地址。
到目前为止我们可以看到,消息其实在我们进行事件调用的时候,已经被提取加工了,它已经由Application进行了预处理,形成了所谓的“事件调用”。那么,我们还能更加自定义的干预消息吗?答案是可以的。
WndProc
//
// 摘要:
// 处理 Windows 消息。
//
// 参数:
// m:
// 要处理的 Windows System.Windows.Forms.Message。
protected override void WndProc(ref System.Windows.Forms.Message e);
对于每个Form来说,我们都可以重写该方法,该方法的参数就是上面提到的Message类的实例,所有的消息在被获取后,正常情况下都会被封装为Message对象,然后由Application工作引擎调用对用的Form.WndProc传入该Messsage,由于Form子类重写了该方法,所以如果希望底层能处理相关的消息,需要通过base.WndProc传递到父类继续调用。下面就是一个代码示例来展示控制如果当前的消息是鼠标左键点击,则弹出MessageBox展示“WndProc MouseClick”:
protected override void WndProc(ref Message m)
{
const int WM_LBUTTONDOWN = 0x0201;// 鼠标左键点击
if (m.Msg == WM_LBUTTONDOWN)
{
MessageBox.Show("WndProc MouseClick");
return;
}
base.WndProc(ref m);
}
IMessageFilter
除了上述的WndProc之外,其实更加便于处理应该的实现IMessageFilter接口,然后让Application将实现该接口的消息过滤器添加到Application中:
public class MyMessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
//返回值为true, 表示消息已被处理,不要再往后传递,因此消息被截获
//返回值为false,表示消息未被处理,需要再往后传递,因此消息未被截获
const int WM_LBUTTONDOWN = 0x0201;// 鼠标左键点击
if (m.Msg == WM_LBUTTONDOWN)
{
MessageBox.Show("MyMessageFilter MouseClick");
return true;
}
return false;
}
}
编写完成后,在应用程序初始化的过程中,添加该过滤器:
Application.AddMessageFilter(new MyMessageFilter());
同样的,我们启动应用程序并点击实验,可以看到正常的MessageBox输出。
WinForm事件与消息的更多相关文章
- 浅谈Winform事件的实现以及模拟其事件的实现(附实现源码)
当我们初学Winform的时候被其神奇的事件功能所吸引,当点击一个按钮时,便会跳到我们所写的点击方法当中去.然而这并不符合我们对方法的理解,究竟.net在后面帮助我们实现了什么.我们怎样模拟其事件的实 ...
- Android基本控件和事件以及消息总结
Android学生空间界面设计涉及到的常用基本控件有TextView,EditText,Button,ImageView,CheckBox,RadioButton,基本事件有触屏和键盘事件,包括onT ...
- PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)
源码地址:https://github.com/Tinywan/PHP_Experience 测试环境配置: 环境:Windows 7系统 .PHP7.0.Apache服务器 PHP框架:ThinkP ...
- Zstack中任务,事件,消息之间的关系
Zstack是Zigbee协议的具体实现,在实现的过程中为了能够更好的对各个模块和功能进行管理,所以加入了OSAL(Operating System Abstraction Layer 操作系统抽象层 ...
- 微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务
http://skaka.me/blog/2016/04/21/springcloud1/ 不同于单一架构应用(Monolith), 分布式环境下, 进行事务操作将变得困难, 因为分布式环境通常会有多 ...
- 零基础逆向工程28_Win32_02_事件_消息_消息处理函数
1 第一个图形界面程序 步骤1:创建Windows应用程序 选择空项目 步骤2:在新建项窗口中选C++代码文件 创建一个新的cpp文件 步骤3:在新的cpp文件中添加:#include <Win ...
- [转帖]微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务
微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务 http://skaka.me/blog/2016/04/21/springcloud1/ APR 21ST, ...
- WinForm事件中的Object sender和EventArgs e参数
Windows程序有一个事件机制.用于处理用户事件. 在WinForm中我们经常需要给控件添加事件.例如给一个Button按钮添加一个Click点击事件.给TextBox文本框添加一个KeyPress ...
- 钉钉自定义机器人配合SVN钩子事件进行消息的推送实践
目前很多公司还是使用SVN(TortoiseSVN)进行版本控制,使用简单,适合管理一般项目.协同办公软件目前钉钉比较成熟,阿里也一直在宣传推广,这两年公司也在使用,主要用于信息的沟通,其它的绩效.考 ...
随机推荐
- docker实现mysql主从复制
目录 一.概述 二.创建master主库 三.创建Slave实例 四.主从配置 五.参考 一.概述 1.原理 master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时 ...
- mybatis gengeator一键生成
- 微信小程序的button按钮设置宽度无效
亲,你是不是也遇到了微信小程序的button按钮设置宽度无效.让我来告诉你怎么弄 方法1. 样式中加入!important,即:width: 100% !important; wxss代码示例 1 2 ...
- OpenCV 生成矩形mask
生成mask的一种操作 cv::Mat mask = cv::Mat::zeros(300, 300, CV_8UC1); mask(cv::Rect(100,150,100, 50)) = 255; ...
- 用tinyxml2读写xml文件_C++实现
下载源代码 开源代码github地址: https://github.com/leethomason/tinyxml2 添加工程文件 将源代码目录中 tinyxml2.h 和 tinyxml2.cpp ...
- Learning ROS: Packaging your ROS project as a snap
Snaps are containerised software packages that are simple to create and install. They auto-update an ...
- Ubuntu16.04 Linux 下安装、配置SSH
本人在Win7+VMware下利用两个ubuntu虚拟机安装.配置.测试了SSH. 在Server端安装openssh-server. sudo apt-get install ssh # 安装ssh ...
- PowerDotNet平台化软件架构设计与实现系列(01):基础数据平台
本系列我将主要通过图片和少许文字讲解通过个人自研的PowerDotNet进行快速开发平台化软件产品. PowerDotNet不仅仅是包含像Newtonsoft.Json.Dapper.Quartz.R ...
- Linux下scp命令
1.scp 是 secure copy 的缩写, scp 是 linux 系统下基于 ssh 登陆进行安全的远程文件拷贝命令. 2.scp 是加密的,rcp 是不加密的,scp 是 rcp 的加强版. ...
- Python常见问题 - python3 使用requests发送HTTPS请求报certificate verify failed 错误
当你使用 requests 发送HTTPS请求时 requests.get(url, parmas=parmas, headers=header, cookies=cookie) 出现了以下错误 HT ...