摘 要:本文主要介绍基于C#的WinForm窗体的消息循环机制,让使用微软的Visual Studio C#工具来编写Windows桌面应用程序的程序员了解其消息处理原理,以便更好更快速地使用该编程工具进行应用程序开发。
关键词:C#; WinForm;消息;代理
编写过Windows桌面应用程序的人都知道,微软的Windows操作系统与应用程序之间的通信绝大部分是基于消息循环机制的。在VC++中,程序使用GetMessage,TranslateMessage,DispatchMessage语句从消息队列中获取消息,转换消息并且将消息分发到目标窗口的过程函数,并由过程函数对不同的Windows消息进行分别处理。
当你将开发平台转向C#的时候,由于C#对消息进行了面向对象的封装,消息被封装成了事件,使我们对消息传送机制的理解蒙上了一层迷雾,下面我们就从实际的代码着手,抽丝剥茧,逐步了解C# WinForm中的消息处理机制。
当我们新建一个WinForm程序后在Program.cs中我们看到Application.Run(new Form1());
Application类具有用于启动和停止应用程序和线程以及处理Windows消息的方法。 通过此语句,当前线程上开始运行标准应用程序消息循环,并使指定窗口可见,消息循环被封装进了Application类的Run()静态方法中。程序结束时调用Exit或者ExitThread来停止消息循环,程序也就随之终止。
我们为Form1窗体中创建鼠标点击事件MyClick,程序自动为我们增加一些代码。
this.MouseClick+=new System.Windows.Forms.MouseEventHandler(this.MyClick);
上面this.MouseClick是C#中定义的鼠标单击事件。它被定义为: public event MouseEventHandler MouseClick;
而MouseEventHandler的定义是public delegate void MouseEventHandler(object sender, MouseEventArgs e);
该语句定义了一个名为MouseEventHandler的委托,那什么是委托呢?
委托类型可以理解成在C++中的函数指针,但不同的是,委托是完全面向对象的,同时封装了对象的实例和方法。本质上,委托把一个实例和该实例上的方法函数封装成一个可调用的实体,它是面向对象的、安全的。
我们可以把第一句代码理解成为this.MouseClick事件添加了一个指向MyClick处理函数的函数指针。C#中事件的处理方法需要使用委托类型对事件进行注册。
当然,你也可以再次调用这句语句对事件添加另一个处理函数如MyClick2,这些对该事件的处理会形成处理函数列表。则在程序运行过程中点击鼠标后在完成MyClick函数后会继续运行MyClick2函数。
由上我们可以大致猜测其封装过程:
Application类将对象发送过来的消息从应用程序消息队列中提取出来后,分发到相应的窗体,并转换成事件。NET框架定义了一个特殊的类型(Delegate委托),该类型提供函数指针的功能。这样,委托就等效于一个类型安全的函数指针或一个回调函数。C#中通过Delegate委托机制将事件与响应函数的函数地址关联起来,并形成一种函数指针列表,当消息到来的时候,即可通过这些函数指针列表逐一调用这些响应函数。
我们通过以下方法自定义一个事件触发,来验证我们以上的猜测。
我们通过手动添加代码来实现自定义的代理事件(同VC++中的自定义消息)
1、声明事件委托。此处int para仅是方便实验,代表所需要的参数列表,但要注意参数列表需要和第3步的参数列表相统一。
public delegate void MyEventHandler(int para);
2、声明事件,event 关键字用于在发行者类中声明事件,委托MyEventHandler作为事件的类型。
public event MyEventHandler MyEvent;
?3、添加事件的处理程序(响应事件的方法)。
public void OnMyEvent(int para)
{
MessageBox.Show(""事件触发,参数为:""+para);
}
4、将指定的事件处理程序邦定到要处理的事件上(订阅事件),注意,此语句需要写在程序执行语句中,如Form_Lord函数内。
this.MyEvent += new MyEventHandler(OnMyEvent);
5、触发事件(调用事件的触发方法)。
MyEvent(3);
6、通过事件委托的回调,执行我们需要的事件处理程序。弹出消息框“事件触发,参数为:3”。
以上实验可以得出结论,C#中的消息通过Application转换成事件以后,通过以上6个步骤完成了事件与处理程序之间的对应关系,在用户触发事件以后,相应的时间处理程序得到准确执行。也可通过以上方法,增加用户自定义事件。
参考文献:
[1] Microsoft Visual Studio 2010文档
[2] 管西京 C#核心开发技术从入门到精通 电子工业出版社 2009
[3](美)斯特劳斯特鲁普 著,王刚 等译 C++程序设计原理与实践 机械工业出版社 2010