在本节中,主要讲对c#中事件的理解。
一、Windows消息
提到事件,就不能不提到windows消息,先简单的回顾一下windows消息传递机制:windows消息服务就是一监听程序,当点击鼠标或者按下键盘键,监听程序都将捕获该事件,并作为windows消息进入windows消息队列,windows根据消息的Message ID将各个消息派发给对应的处理程序(当然,也会将没有对应处理程序的消息丢弃)。比如,在点击了某个窗体上的一个按钮,windows最终会将该点击事件消息传递给该按钮的点击事件处理程序(按钮也是一个独立的窗体,窗体建立的时候都会想操作系统Register)。
二、事件处理过程模拟
理解了以上基础,在言归正传。以Button为例。
首先,Button也是一个类(这一点很重要,一般对于很抽象的概念,看到本质很重要),那么当Button类的实例接收到这一点击事件的消息时,在该类中肯定定义了一个对应的处理函数。不妨将Button想象成如下样子:
public class Button
{
//...................
private void ClickEventMethod()
{
//.......
}
//..................
}
该类定义了ClickEventMethod方法来处理按钮点击事件,有问题么,呵呵,估计都发现了,处理过程代码都在内部写死在,程序员还做什么。
熟悉C++的朋友可能都想到了,在该类中不写ClickEventMethod函数的实现,仅仅定义一个public型函数指针,把实现函数留给程序员去写,同时程序员负责在程序中把实现函数关联到此函数指针上。不妨再将Button想象成如下样子:
按钮(Button)类
public class Button
{
//C#没有指针概念,这里先借用一下C++语法,
//这里只要知道fpClickEventMethod是一个函数指针,指向点击事件的处理函数就可以了
void (*fpClickEventMethod)();
//..................
}
同时在放有该Button按钮的窗体类中添加如下的代码
public partial class DelegateTest : Form
{
//...............
this.btnButton.fpClickEventMethod = ClickEventMethod;
private void ClickEventMethod()
{
//..............
}
//................
}
好,问题解决了,当点击按钮事件传到到Button窗体时,该类对象找到fpClickEventMethod函数指针指向的函数并调用,最终的处理程序(ClickEventMethod实现)完全在程序员的控制下。
可是c#中并没有函数指针这东东,怎么办。我们在前面一节中讲的委托很好的解决了这个问题。
三、委托实现事件处理,函数回调。
新建一窗体,取名叫frmTest,在窗体上放一Name为btnTest的按钮,双击按钮,frmTest.cs代码如下:
public partial class frmTest : Form
{
//................
private void btnTest_Click(object sender, EventArgs e)
{
}
}
frmTestDesigner.cs代码如下:
partial class frmTest
{
private void InitializeComponent()
{
this.btnTest = new System.Windows.Forms.Button();
this.btnTest.Click += new System.EventHandler(this.btnTest_Click);
//................
}
//................
}
两个单元合并成了一个完整的frmTest类,点击事件的实现函数在frmTest.cs中,定义如下:
private void btnTest_Click(object sender, EventArgs e)
该实现函数通过frmTestDesigner.cs中的如下语句绑定在一个叫Click的东东上。
this.btnTest.Click += new System.EventHandler(this.btnTest_Click)
在Click上点右键选择“转到定义”,看到如下代码:
public event EventHandler Click
这里EventHandler是什么东东,继续在EventHandler上点右键选择“转到定义”,看到如下代码:
public delegate void EventHandler(object sender, EventArgs e)
到这里,终于真相大白,原来EventHandler是一个委托类,在Button中定义了该委托类的一个对象变量Click(可以理解成函数指针),该委托最终绑定到btnTest_Click(object sender, EventArgs e)函数上。当按钮接收到点击事情消息时,转到Click委托,最终找到Click委托指向的的btnTest_Click处理函数。