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事件与消息的更多相关文章

  1. 浅谈Winform事件的实现以及模拟其事件的实现(附实现源码)

    当我们初学Winform的时候被其神奇的事件功能所吸引,当点击一个按钮时,便会跳到我们所写的点击方法当中去.然而这并不符合我们对方法的理解,究竟.net在后面帮助我们实现了什么.我们怎样模拟其事件的实 ...

  2. Android基本控件和事件以及消息总结

    Android学生空间界面设计涉及到的常用基本控件有TextView,EditText,Button,ImageView,CheckBox,RadioButton,基本事件有触屏和键盘事件,包括onT ...

  3. PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)

    源码地址:https://github.com/Tinywan/PHP_Experience 测试环境配置: 环境:Windows 7系统 .PHP7.0.Apache服务器 PHP框架:ThinkP ...

  4. Zstack中任务,事件,消息之间的关系

    Zstack是Zigbee协议的具体实现,在实现的过程中为了能够更好的对各个模块和功能进行管理,所以加入了OSAL(Operating System Abstraction Layer 操作系统抽象层 ...

  5. 微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务

    http://skaka.me/blog/2016/04/21/springcloud1/ 不同于单一架构应用(Monolith), 分布式环境下, 进行事务操作将变得困难, 因为分布式环境通常会有多 ...

  6. 零基础逆向工程28_Win32_02_事件_消息_消息处理函数

    1 第一个图形界面程序 步骤1:创建Windows应用程序 选择空项目 步骤2:在新建项窗口中选C++代码文件 创建一个新的cpp文件 步骤3:在新的cpp文件中添加:#include <Win ...

  7. [转帖]微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务

    微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务 http://skaka.me/blog/2016/04/21/springcloud1/ APR 21ST,  ...

  8. WinForm事件中的Object sender和EventArgs e参数

    Windows程序有一个事件机制.用于处理用户事件. 在WinForm中我们经常需要给控件添加事件.例如给一个Button按钮添加一个Click点击事件.给TextBox文本框添加一个KeyPress ...

  9. 钉钉自定义机器人配合SVN钩子事件进行消息的推送实践

    目前很多公司还是使用SVN(TortoiseSVN)进行版本控制,使用简单,适合管理一般项目.协同办公软件目前钉钉比较成熟,阿里也一直在宣传推广,这两年公司也在使用,主要用于信息的沟通,其它的绩效.考 ...

随机推荐

  1. 工作多年后再来聊聊IO

    IO模型 IO是Input/Output的缩写.Linix网络编程中有五种IO模型: blocking IO(阻塞IO) nonblocking IO(非阻塞IO) IO multiplexing(多 ...

  2. 修改python import模块中的变量

    可以直接通过 模块名.变量名=xx 的方式修改模块中的全局变量,测试代码如下 模块:test_model.py x = 111 def inc_x(): global x x = x + 1 测试脚本 ...

  3. 3k+2形式的素数相关的两个命题的证明

  4. 每天迁移MySQL历史数据到历史库Python脚本

    #!/usr/bin/env python # coding:utf-8 #__author__ = 'Logan'      import MySQLdb import sys import dat ...

  5. 办公室文员必备python神器,将PDF文件表格转换成excel表格!

    [阅读全文] 第三方库说明 # PDF读取第三方库 import pdfplumber # DataFrame 数据结果处理 import pandas as pd 初始化DataFrame数据对象 ...

  6. python 加速运算

    原文链接:https://blog.csdn.net/qq_27009517/article/details/103805099 一.加速查找 1.用set而非list import time dat ...

  7. RT-Thread 4.0 + STM32F407 学习笔记1

    RT Thread 4.0提供了新的BSP框架 新 BSP 框架的主要特性如下: 提供多系列 BSP 模板,大大降低新 BSP 的添加难度: 每个 BSP 都配有齐全的驱动文件,开发者可以方便地使用所 ...

  8. Python - 面向对象编程 - 小实战(2)

    需求 小明和小美都爱跑步 小明体重 75 公斤 小美体重 45 公斤 每次跑步会减肥 0.5 公斤 每次吃东西体重增加 1 公斤 需求分析 小明.小美都是一个具体的对象,他们都是人,所以应该抽象成人类 ...

  9. DHCP 协议及其交互过程

    1. DHCP用途简介: DHCP服务应用于大型局域网络中,使网络中的主机自动获取IP地址,网关,DNS服务器等信息,能够提升IP地址的利用率.一般情况下,我们的家用.公司.公共场合使用的路由器都具有 ...

  10. poll?transport=longpoll&connection...烦人的请求c

    1.问题描述: 最近使用miniui做了一个后台管理系统,打开浏览器调试时,总发现一堆无关的请求,结构大致是:poll?transport=longpoll&connection.....一直 ...