事件(event)这个词儿对于初学者来说往往总是显得有些神秘不易弄懂而这些东西却往往又是编程中常用且非常重要的东西大家都知道windows消息处理机制的重要其实C#事件就是基于windows消息处理机制的只是封装的更好让开发者无须知道底层的消息处理机制就可以开发出强大的基于事件的应用程序来
先来看看事件编程有哪些好处
在以往我们编写这类程序中往往采用等待机制为了等待某件事情的发生需要不断地检测某些判断变量而引入事件编程后大大简化了这种过程
使用事件可以很方便地确定程序执行顺序
当事件驱动程序等待事件时它不占用很多资源事件驱动程序与过程式程序最大的不同就在于程序不再不停地检查输入设备而是呆着不动等待消息的到来 每个输入的消息会被排进队列等待程序处理它如果没有消息在等待则程序会把控制交回给操作系统以运行其他程序
事件简化了编程操作系统只是简单地将消息传送给对象由对象的事件驱动程序确定事件的处理方法操作系统不必知道程序的内部工作机制只是需要知道如何与对象进行对话也就是如何传递消息
有了这么多好处看来我们的确有必要掌握它俗话说难了不会会了不难就让我们一步一步开始吧
要讲事件必然要讲到委托(delegate)它们之间的关系可以通过一个浅显的比方来说明这个比方可能不是十分恰当比如你要租一个房屋这是一个事件那么委托就是房屋租赁中介当你把租房子的消息告知中介后中介就会产生出一套符合你要求的房屋租赁方案来再由中介执行这套方案你便租得了这个房屋即事件被处理了当然你也可以不通过中介直接找房东但如果没有互联网等工具你如何得到谁出租房屋的信息?话题扯远了
委托(delegate)
委托可以理解成为函数指针不同的是委托是面向对象而且是类型安全的关于委托的理解可以参考我的另一篇文章《C#委托之个人理解》
事件(event)
我们可以把事件编程简单地分成两个部分事件发生的类(书面上叫事件发生器)和事件接收处理的类事件发生的类就是说在这个类中触发了一个事件但这个类并不知道哪个个对象或方法将会加收到并处理它触发的事件所需要的是在发送方和接收方之间存在一个媒介这个媒介在NET Framework中就是委托(delegate)在事件接收处理的类中我们需要有一个处理事件的方法好了我们就按照这个顺序来实现一个捕获键盘按键的程序来一步一步说明如何编写事件应用程序
首先创建一个自己的EventArgs类
引自MSDN:
EventArgs是包含事件数据的类的基类此类不包含事件数据在事件引发时不向事件处理程序传递状态信息的事件会使用此类如果事件处理程序需要状态信息则应用程序必须从此类派生一个类来保存数据
因为在我们键盘按键事件中要包含按键信息所以要派生一个KeyEventArgs类来保存按键信息好让后面知道按了哪个键
internal class KeyEventArgs : EventArgs
{
private char keyChar;
public KeyEventArgs( char keyChar ) : base()
{
thiskeyChar = keyChar;
}
public char KeyChar
{
get
{
return keyChar;
}
}
}
再创建一个事件发生的类KeyInputMonitor这个类用于监控键盘按键的输入并触发一个事件
internal class KeyInputMonitor
{
// 创建一个委托返回类型为void两个参数
public delegate void KeyDown( object sender KeyEventArgs e );
// 将创建的委托和特定事件关联在这里特定的事件为OnKeyDown
public event KeyDown OnKeyDown;
public void Run()
{
bool finished = false;
do
{
ConsoleWriteLine( Input a char );
string response = ConsoleReadLine();
char responseChar = ( response == ) ? : charToUpper( response[] );
switch( responseChar )
{
case X:
finished = true;
break;
default:
// 得到按键信息的参数
KeyEventArgs keyEventArgs = new KeyEventArgs( responseChar );
// 触发事件
OnKeyDown( this keyEventArgs );
break;
}
}while( !finished );
}
}
这里注意OnKeyDown( this KeyEventArgs );一句这就是触发事件的语句并将事件交由KeyDown这个委托来处理委托指定事件处理方法去处理事件这就是事件接收方的类的事情了参数 this是指触发事件的对象就是本身这个对象keyEventArgs包含了按键信息
最后创建一个事件接收方的类这个类先产生一个委托实例再把这个委托实例添加到产生事件对象的事件列表中去这个过程又叫订阅事件然后提供一个方法回显按键信息
internal class EventReceiver
{
public EventReceiver( KeyInputMonitor monitor )
{
// 产生一个委托实例并添加到KeyInputMonitor产生的事件列表中
monitorOnKeyDown += new KeyInputMonitorKeyDown( thisEcho );
}
private void Echo(object sender KeyEventArgs e)
{
// 真正的事件处理函数
ConsoleWriteLine( Capture key: {} eKeyChar );
}
}
看一下如何调用
public class MainEntryPoint
{
public static void Start()
{
// 实例化一个事件发送器
KeyInputMonitor monitor = new KeyInputMonitor();
// 实例化一个事件接收器
EventReceiver eventReceiver = new EventReceiver( monitor );
// 运行
monitorRun();
}
}
总结
C#中使用事件需要的步骤
创建一个委托
将创建的委托与特定事件关联(Net类库中的很多事件都是已经定制好的所以他们也就有相应的一个委托在编写关联事件处理程序也就是当有事件发生时我们要执行的方法的时候我们需要和这个委托有相同的签名)
编写事件处理程序
利用编写的事件处理程序生成一个委托实例
把这个委托实例添加到产生事件对象的事件列表中去这个过程又叫订阅事件
C#中事件产生和实现的流程
定义A为产生事件的实例a为A产生的一个事件
定义B为接收事件的实例b为处理事件的方法
A由于用户(程序编写者或程序使用者)或者系统产生一个a事件(例如点击一个Button产生一个Click事件)
A通过事件列表中的委托对象将这个事件通知给B
B接到一个事件通知(实际是Bb利用委托来实现事件的接收)
调用Bb方法完成事件处理