100165343.htm
来自「C#高级编程(第三版),顶死你们。。 。up」· HTM 代码 · 共 161 行 · 第 1/2 页
HTM
161 行
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>
6.2.2 生成事件
</title></head>
<body>
<div class="area">
<div class="col1">
<div class="lineBlue">
</div>
<!-- title -->
<div class="arcTitle">
<h1>
<a href="../16">
C#高级编程(第3版)【全文连载】
</a>
</h1>
<div style="text-align: center; font-size: 15px">
<a href="100165343.htm">
6.2.2 生成事件
</a>
</div>
<div style="text-align: center; font-size: 15px">
<a class="url" href="../../default.htm">http://book.csdn.net/</a>
2006-10-13 14:41:00
</div>
<div style="margin: 0px auto; width: 700px; border: solid 1px #0b5f98;">
<div style="float: left; width: 16px; background-color: #0b5f98; color: White; padding: 1px;">
图书导读
</div>
<div style="float: right; width: 670px; text-align: left; line-height: 16pt; padding-left: 2px">
<!--导读-->
<h1 id="divCurrentNode" style="color: #b83507; width: 100%; text-align: left; font-size: 12px; padding-left: 2px">当前章节:<a href='100165343.htm'><font color='red'>6.2.2 生成事件</font></a></h1>
<div id="divRelateNode" style="padding-left: 2px">
<div style='float:left;width:49%'>·<a href='100165340.htm'>6.1.4 多播委托</a></div><div style='float:right;width:49%'>·<a href='100165341.htm'>6.2 事件</a></div><div style='float:left;width:49%'>·<a href='100165342.htm'>6.2.1 从客户的角度讨论事件</a></div><div style='float:right;width:49%'>·<a href='100165344.htm'>6.3 小结</a></div><div style='float:left;width:49%'>·<a href='100165358.htm'>9.1 对象组</a></div><div style='float:right;width:49%'>·<a href='100165359.htm'>9.1.1 数组列表</a></div></div>
</div>
</div>
</div>
<!-- main -->
<div id="main">
<div id="text"> <link href="css.css" rel="stylesheet" type="text/css" /><h3 style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 0cm; MARGIN-RIGHT: 0cm; FTEL: 8.15pt"><span lang="EN-US">6.2.2 </span><span style="FONT-FAMILY: 黑体">生成事件</span></h3>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">接收事件并响应它们仅是事件的一个方面。为了使事件真正发挥作用,还需要在代码中生成和引发事件。下面的例子将介绍如何创建、引发、接收和取消事件。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">这个例子包含一个窗体,它会引发另一个类正在监听的事件。在引发事件后,接收对象就确定是否执行一个过程,如果该过程未能继续,就取消事件。本例的目标是确定当前时间的秒数是大于</span><span lang="EN-US">30</span><span style="FONT-FAMILY: 宋体">还是小于</span><span lang="EN-US">30</span><span style="FONT-FAMILY: 宋体">。如果秒数小于</span><span lang="EN-US">30</span><span style="FONT-FAMILY: 宋体">,就用一个表示当前时间的字符串设置一个属性;如果秒数大于</span><span lang="EN-US">30</span><span style="FONT-FAMILY: 宋体">,就取消事件,把时间字符串设置为空。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">用于生成事件的窗体包含一个按钮和一个标签。下载的示例代码把按钮命名为</span><span lang="EN-US">btnRaise</span><span style="FONT-FAMILY: 宋体">,标签命名为</span><span lang="EN-US">lblInfo</span><span style="FONT-FAMILY: 宋体">,您也可以给标签使用其他名称。在创建窗体,添加两个控件后,就可以创建事件和相应的委托了。在窗体类的类声明部分,添加如下代码:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public delegate void ActionEventHandler(object sender, ActionCancelEventArgs ev);</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public static event ActionEventHandler Action;</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">这两行代码的作用是什么?首先,我们声明了一种新的委托类型</span><span lang="EN-US">ActionEventHandler</span><span style="FONT-FAMILY: 宋体">。必须创建一种新委托,而不使用</span><span lang="EN-US">Framework</span><span style="FONT-FAMILY: 宋体">预定义的委托,其原因是后面要使用定制的</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">类。方法签名必须与委托匹配。有了一个要使用的委托后,下一行代码就定义事件。在本例中定义了</span><span lang="EN-US">Action</span><span style="FONT-FAMILY: 宋体">事件,定义事件的语法要求指定与事件相关的委托。还可以使用在</span><span lang="EN-US">Framework</span><span style="FONT-FAMILY: 宋体">中定义的委托。从</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">类中派生出了近</span><span lang="EN-US">100</span><span style="FONT-FAMILY: 宋体">个类,应该可以找到一个自己能使用的类。但本例使用的是定制的</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">类,所以必须创建一个与之匹配的新委托类型。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">基于</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">的新类</span><span lang="EN-US">ActionCancelEventArgs</span><span style="FONT-FAMILY: 宋体">实际上派生于</span><span lang="EN-US">CancelEventArgs</span><span style="FONT-FAMILY: 宋体">,而</span><span lang="EN-US">CancelEventArgs</span><span style="FONT-FAMILY: 宋体">派生于</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">。</span><span lang="EN-US">CancelEventArgs</span><span style="FONT-FAMILY: 宋体">添加了</span><span lang="EN-US">Cancel</span><span style="FONT-FAMILY: 宋体">属性,该属性是一个布尔值,它通知</span><span lang="EN-US">sender</span><span style="FONT-FAMILY: 宋体">对象,接收器希望取消或停止事件的处理。在</span><span lang="EN-US">ActionCancelEventArgs</span><span style="FONT-FAMILY: 宋体">类中,还添加了</span><span lang="EN-US">Message</span><span style="FONT-FAMILY: 宋体">属性,这是一个字符串属性,包含事件处理状态的文本信息。下面是</span><span lang="EN-US">ActionCancelEventHandler</span><span style="FONT-FAMILY: 宋体">类的代码:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public class ActionCancelEventHandler : System.ComponentModel. CancelEventArgs</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> string _msg = "";</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> public ActionCancelEventArgs() : base() {}</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> public ActionCancelEventArgs(bool cancel) : base(cancel) {}</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> public ActionCancelEventArgs(bool cancel, string message) : base(cancel)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> _msg = message;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 27.65pt"><span lang="EN-US">}</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> public string Message</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> get {return _msg;}</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> set {_msg = value;}</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">}</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">可以看出,所有基于</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">的类都负责在发送器和接收器之间来回传送事件的信息。在大多数情况下,</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">类中使用的信息都被事件处理程序中的接收器对象使用。但是,有时事件处理程序可以把信息添加到</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">类中,使之可用于发送器。这就是本例使用</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">类的方式。注意在</span><span lang="EN-US">EventArgs</span><span style="FONT-FAMILY: 宋体">类中有两个可用的构造函数。这种额外的灵活性增加了该类的可用性。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">目前声明了一个事件,定义了一个委托,并创建了</span><span lang="EN-US">ActionCancelEventArgs</span><span style="FONT-FAMILY: 宋体">类。下一步需要引发事件。真正需要做的是用正确的参数调用事件,如本例所示:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">ActionCancelEventArgs ev = new CancelEventArgs();</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">Action(this, ev);</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">这非常简单。创建新的</span><span lang="EN-US">ActionCancelEventArgs</span><span style="FONT-FAMILY: 宋体">类,并把它作为一个参数传递给事件。但是,这有一个小问题。如果事件不会在任何地方使用,该怎么办?如果还没有为事件定义处理程序,该怎么办?</span><span lang="EN-US">Action</span><span style="FONT-FAMILY: 宋体">事件实际上是空的。如果试图引发该事件,就会得到一个空引用异常。如果要派生一个新的窗体类,并使用该窗体,把</span><span lang="EN-US">Action</span><span style="FONT-FAMILY: 宋体">事件定义为基事件,则只要引发了</span><span lang="EN-US">Action</span><span style="FONT-FAMILY: 宋体">事件,就必须执行其他一些操作。目前,我们必须在派生的窗体中激活另一个事件处理程序,这样才能访问它。为了使这个过程容易一些,并捕获空引用错误,就必须创建一个名为</span><span lang="EN-US">OnEventName</span><span style="FONT-FAMILY: 宋体">的方法,其中</span><span lang="EN-US">EventName</span><span style="FONT-FAMILY: 宋体">是事件名。在这个例子中,有一个名为</span><span lang="EN-US">OnAction</span><span style="FONT-FAMILY: 宋体">的方法,下面是</span><span lang="EN-US">OnAction</span><span style="FONT-FAMILY: 宋体">方法的完整代码:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">protected void OnAction(object sender, ActionCancelEventArgs ev)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> if(Action != null)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US"> Action(sender, ev);</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">}</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt; FTEL: 0cm"><span style="FONT-FAMILY: 宋体">代码并不多,但完成了需要的工作。把该方法声明为</span><span lang="EN-US">protected</span><span style="FONT-FAMILY: 宋体">,就只有派生类可以访问它。事件在引发之前还会进行空引用测试。如果派生一个包含该方法和事件的新类,就必须重写</span><span lang="EN-US">OnAction</span><span style="FONT-FAMILY: 宋体">方法,然后再连接事件。为此,必须在重写代码中调用</span><span lang="EN-US">base.OnAction()</span><span style="FONT-FAMILY: 宋体">。否则就不会引发该事件。在整个</span><span lang="EN-US">.NET Framework</span><span style="FONT-FAMILY: 宋体">中都用这个命名约定,并在</span><span lang="EN-US">.NET SDK</span><span style="FONT-FAMILY: 宋体">文档中对这一命名规则进行了说明。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">注意传送给</span><span lang="EN-US">OnAction</span><span style="FONT-FAMILY: 宋体">方法的两个参数。它们看起来很熟悉,因为它们与需要传送给事件的参数相同。如果事件需要从另一个对象中引发,而不是从定义方法的对象中引发,就需要把访问修饰符设置为</span><span lang="EN-US">internal</span><span style="FONT-FAMILY: 宋体">或</span><span lang="EN-US">public</span><span style="FONT-FAMILY: 宋体">,而不能设置为</span><span lang="EN-US">protected</span><span style="FONT-FAMILY: 宋体">。有时让类只包含事件声明和从其他类中调用的事件是有意义的。仍可以创建</span><span lang="EN-US">OnEventName</span><span style="FONT-FAMILY: 宋体">方法,但它们是静态方法。</span></p>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?