| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4361 人关注过本帖, 1 人收藏
标题:【交流探讨】说说你本人对“事件”的理解……
只看楼主 加入收藏
铲铲
Rank: 7Rank: 7Rank: 7
等 级:贵宾
威 望:34
帖 子:506
专家分:0
注 册:2006-5-2
收藏
得分:0 
其实在MSDN上已经有大量关于事件的文章,而且写得非常规范,但是比较难以理解
要说事件,先说委托,要说委托,先说指针,另外,再加上对Windows消息循环的说明。
我们知道Windows是基于消息的操作系统,一个典型的Windows应用程序启动后就开始执行一个等待消息的无限循环,操作系统会将消息分发给线程,线程又将消息用switch开关分发给不同的函数得以执行。Windows消息模型和.net事件模型行为非常相似,不过他们不处于一个层次上,Windows消息比较原始。
再来说委托,在.net中,函数体比较标准的叫法叫做“方法”,我们可以为方法指定形参,行参可以是一些简单的数据类型,如int等,甚至也可以是对象等引用类型。但我们却没有办法将另一个方法名当作形参传递给这个方法。委托的作用就是封装一个方法,使其看起来像是一个引用类型,从而可以当作方法的形参而传递。如果放在c++里,委托更像一个指向方法的指针,C#中不提倡指针(并非不允许,如果你愿意可以在unchecked语句块中使用指针),代替指针行使功能的就是委托。
事件是一种特殊的委托,它特殊在什么地方呢?特殊再它是一个多路广播委托,这个怎么理解?通常我们所声明的代理是一个单播代理,也就是一次只能有一个方法委托给它,但事件不同,可以将多个方法委托给它,当该代理被调用的时候,它将同时通知所有委托到它上面的方法开始执行。好比,声明事件的类是事件的发布者,而其他类里注册该事件方法的称之为订阅者。如果订阅书刊一样,订阅者实现约定好要订阅的书刊(事件),当书刊被印刷出版(引发了事件)以后,书刊被送达订阅者手中(执行方法)。

从声明事件的语句上便可看出:
先声明一个代理:
delegate void EventHandler();
再在该代理的基础上声明事件:
event EventHandler Event

正因为事件是一个多路广播委托,因此注册事件处理程序和注销事件处理程序就是用+=和-=二元运算符来操作,而不是使用等号。这一点应该不难理解吧? 事件维护一个列表用来存放代理,当事件被引发时,通知列表中的所有代理。而等号却只能赋予其一个代理,且下次等号赋值将覆盖上一次赋予的代理,形成不了列表,也就不能产生多路广播委托的效果了。实际上,+=和-=这两个二元运算符在Event中进行了重载。

要使用事件,必须先注册他(也就是订阅)
注册一个事件:
Event += new EventHandler(EventMethod)
也可以注册多个事件:
Event += new EventHandler(EventMethod1);
Event += new EventHandler(EventMethod2);
...

在VS中,注册事件这个过程被隐藏了。以一个按钮控件来说,只需要双击该按钮,就默认注册了按钮的Click事件,并且VS自动将焦点定位到了当Click事件引发时执行的方法内了。如果你打开窗体名称.Designer.cs文件,展开InitializeComponent方法,就可以看到如上注册事件的语句了。
Button1.Click += EventHandler(Button1_Click);

订阅了事件,并不意味着订阅该事件的方法就会执行,如上述,只有在用户单击了按钮的时候,Click事件发生,Button1_Click方法才得以执行。


那么上面所说的都是针对订阅者的,我们清楚认识到要引发事件必须单击按钮。不过,如果你在开发一个控件、组件、类的时候,在你的控件、组件或类里声明了事件,那么事件到底在何时,由谁来引发呢?答案是:你自己!
假设,我们设计一个控件,声明了一个事件:
delegate void EventHandler(object sender, EventArgs e);
event EventHandler PreProcess;
声明一个方法:
void StartProcess();
我们希望使用该控件的用户在调用StartProcess方法,方法执行前引发Event事件,以便于用户有机会在真正处理开始前有机会做一些事情(比如在窗体上显示“正在处理”字样),那么我们就需要在StartProcess方法开始时,引发该事件:
void StartProcess()
{
    if (PreProcess != null)
        PreProcess(this, new EventArgs());
    ...//剩下的处理代码。
}

而在使用该控件的窗体中,
设一个方法:
void Control1_PreProcess(object sender, EventArgs e)
{
    ...//当处理开始时要执行的代码
}
以该方法注册到PreProcess事件(这段代码可以放在这个事件引发之前就执行的其他方法体中):
Control1.PreProcess += new EventHandler(Control1_PreProcess);

后记:
通常大多数朋友使用.net已有的事件,实际上大多数时候我们是事件的订阅者,而要开发控件、组件、类时,我们就需要学习如何发布事件,以及如何在适当的时机引发事件。
当然,我上面所述尽量以一种通俗的说法来阐明事件的原理,以及如何编写它、使用它。限于水平,难免出错欢迎指正。
另外,如果要想编写优秀的、高质量的事件,那么MSDN上关于事件编写的原则不得不熟悉一下,下面简要摘抄几条:
1、通常,我们应该以使用.net已定义的EvengHandler代理和事件所需传递参数EventArgs类来声明事件,如果这个代理和EventArgs类不能满足要求,应当从它们开始继承你自己的代理和EventArgs类。
2、通常,事件应当传递两个参数,即object sender,表示引发事件的发布者(控件、组件),和一个EventArgs e,表示事件所需传递的参数,不建议自行构造参数列表。
3、事件没有返回值,因此代理的返回值应为void,且注册事件的方法也是void。事件的发布者通常只是负责引发事件,它们不关心事件的返回,也关心不了。
4、如果可能,请使用EventHandler的泛型版本:EventHandler<T>,以保持设计一致。
收到的鲜花
  • 静夜思2008-10-24 22:43 送鲜花  50朵   附言:好文章+原创
  • skyzoneskyzone2008-10-29 12:56 送鲜花  3朵   附言:我很赞同

铲铲是也
2008-10-24 14:01
小仙
Rank: 7Rank: 7Rank: 7
来 自:光之谷
等 级:贵宾
威 望:39
帖 子:1812
专家分:1
注 册:2008-8-8
收藏
得分:0 
铲铲回帖质量都很高。对大家很是有帮助,我也研究下,争取发表一点看法。


仁者乐膳,智者乐睡。我都爱~
2008-10-24 17:52
馨欣
Rank: 1
等 级:新手上路
帖 子:10
专家分:0
注 册:2008-10-26
收藏
得分:0 
以我理解事件是一种瞬间的动作,控件触发后所要进行的代码操作。
2008-10-26 13:07
小仙
Rank: 7Rank: 7Rank: 7
来 自:光之谷
等 级:贵宾
威 望:39
帖 子:1812
专家分:1
注 册:2008-8-8
收藏
得分:0 
回复 23# 馨欣 的帖子
很精练的解释。。。


仁者乐膳,智者乐睡。我都爱~
2008-10-26 13:40
Soul寂
Rank: 1
等 级:新手上路
帖 子:117
专家分:1
注 册:2008-9-29
收藏
得分:0 
回复 21# 铲铲 的帖子
Nice,这才像个版主的样子!
2008-10-26 21:59
铲铲
Rank: 7Rank: 7Rank: 7
等 级:贵宾
威 望:34
帖 子:506
专家分:0
注 册:2006-5-2
收藏
得分:0 
但其实事件从引发到返回事件引发者并不是瞬间完成的。
当事件的发布者引发事件以后,执行就在该处被阻塞,直到订阅者订阅该事件的方法执行完毕,执行才会继续往下。因此,要说事件时“瞬间”的,还需说明尺度。

除非,你希望启动一个线程,用此线程来引发事件。但这会使程序更加复杂化。有可能客户端订阅事件的方法中也会考虑启动线程。
因此使用事件的准则就是尽快执行尽快返回。

铲铲是也
2008-10-27 20:29
天使不哭
Rank: 6Rank: 6
等 级:贵宾
威 望:23
帖 子:677
专家分:22
注 册:2006-7-9
收藏
得分:0 
好久没来了,上来看看兄弟们

C#Winform技术群:25380362
博客:http:///boyliupan/
2008-11-05 22:07
小仙
Rank: 7Rank: 7Rank: 7
来 自:光之谷
等 级:贵宾
威 望:39
帖 子:1812
专家分:1
注 册:2008-8-8
收藏
得分:0 
嘿嘿,负责接待的阿达呢?也很久没来了。


仁者乐膳,智者乐睡。我都爱~
2008-11-05 22:10
yuzlooyuzl
Rank: 1
来 自:新疆
等 级:新手上路
帖 子:17
专家分:0
注 册:2008-9-10
收藏
得分:0 
初学C#编程··希望各位能多指导哈·········

[b]世人笑我太疯癫!我笑世人看不穿![/b]
2008-11-06 20:32
有敌手
Rank: 1
等 级:新手上路
帖 子:41
专家分:0
注 册:2008-2-12
收藏
得分:0 
把一个程序抽象成一个人,程序的事件就是这个人的动作
菜鸟的感想...
2008-11-12 18:36
快速回复:【交流探讨】说说你本人对“事件”的理解……
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.013507 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved