前面已经大致讲述了C#委托的一些基础知识点,本文接下来的内容是C#中的事件(Event),在此我提个建议,如果是刚接触C#的委托类型的朋友可以先看到这里,等熟悉了委托的使用之后(大约1-2天)再来了解C#中事件的使用,以免看了以下内容发生思维紊乱的现象。之所以这么说并没有些许自大之意,而相反的是恰恰是认为自己的文章写得结构混乱,不足以明理,如果同时看了委托(delegate)和事件(event)容易知识点混淆,所以只是稍作提醒。

  好了,废话不多说,现在进入正题:

  事件是什么?C#事件是一种具有特殊签名的委托,且在声明事件类型的时候用event关键字修饰。

  说到事件,大家第一个想到的一般都是按钮点击事件,既然说到按钮点击事件,下面就着按钮事件作为例子说开去。

  首先,在Winform界面拖拽一个按钮,双击按钮,代码会自动定位到按钮点击函数,右击点击事件的函数名,查找所有引用,可以看到总共包括以下两处引用:

private void button1_Click(object sender, EventArgs e) {}
this.button1.Click += new System.EventHandler(this.button1_Click);

  在上面为什么我要特别提到定位到第一个语句是一个函数,而不是事件,因为真正的时间是那个 button1.Click 而不是那个 button1_Click ,因为经常听到有人提到说“双击按钮定位到按钮点击事件”,个人感觉这个说法对事件的概念有失偏颇,顺带地提一提。

  在此可以看到函数的参数列表(object sender, EventArgs e),这个参数列表必须是确定的,一个表示点击事件的执行者,一个表示事件参数类,不局限于object和EventArgs,但必须是这个两个类的子类或本身。

  下面看一下创建一个事件的步骤:1

  (1)、定义delegate对象类型,它有两个参数,第一个参数是事件发送者对象,第二个参数是事件参数类对象

  (2)、定义事件参数类,此类应当从System.EventArgs类派生

  (3)、定义事件处理方法,此方法符合步骤(1)定义的委托签名

  (4)、用event关键字定义事件对象,它同时也是一个delegate对象

  (5)、用+=操作符添加事件到事件队列当中,-=操作符把事件从事件队列中删除

  (6)、在需要触发事件的地方调用delegate的方式写事件触发方法。一般来说,此方法应为protected访问限制,既不能以public方式调用,但可以被子类继承。

  下面我们通过模拟一个Button点击事件来深入了解:

 using System;
namespace ConsoleApplication {
//(1)定义一个delegate对象类型
delegate void myEventHandle(object sender, EventArgs e);
class MyEventArg : EventArgs {
//(2)定义事件类,应派生于EventArgs类
public string EventArgsName() {
return "[MyEventArgsName]";
}
}
class _Button {
//(4)定义事件对象,注意关键字和类型
public event myEventHandle Click;
protected void OnUtilEvent(MyEventArg e) {
if(null != Click) {
Click(this, e);
}
}
public void RaiseEvent() {
MyEventArg e = new MyEventArg();
OnUtilEvent(e);
}
public string ButtonName() {
return "[myButtonName]";
}
}
class EventTest {
//(3)定义事件处理方法,保证函数列表和返回值的有效性
static void _Button_Click(object sender, EventArgs e) {
Console.WriteLine("\nYou have clicked the button");
Console.WriteLine("The eventObject is :\t"+(sender as _Button).ButtonName());
Console.WriteLine("The eventArgs is:\t"+(e as MyEventArg).EventArgsName());
}
static void Main() {
_Button _button = new _Button();
//(5)用操作符把事件添加到事件队列当中
_button.Click += new myEventHandle(_Button_Click);
Console.Write("Do you want to click the button(Y/N)");
if (Console.ReadKey().KeyChar == 'Y')
_button.RaiseEvent();
else
Console.WriteLine("The event does not raise");
}
}
}

  其中我已经把创建步骤写成注释表明在代码中了,模拟鼠标点击事件我们修改为按下“Y”触发,当看到 _button.Click += new myEventHandle(_Button_Click); 有没有恍然大悟的感觉。其实原理并不难,多练习几次条理就清晰。书读百遍,其义自现,说的亦是如此。

  使用某IDE编写以上例子的时候可能在 if(null != Click){ Click(this,e); } 这段语句时会报一个[NOTICE],提示该表示方法可以简单化,可以改成 Click?.Invoke(this, e); 注意这不是错误,如此表示只是为了降低理解难度,其实两个语句的作用是一样的,判断Click对象是否为null,然后执行该事件。

  事件发布器:

  通过一个例子来直接了解事件发布

 using System;
namespace ConsoleApplication {
public delegate void myEventHandle(object sender,FoodEventArg e);
public class FoodEventArg : EventArgs {
private string food;
public FoodEventArg(string food) {
this.food = food;
}
public string getFood() {
return food;
}
}
class Person {
private string name;
public Person(string name) {
this.name = name;
}
public void FoodRecive(object sender,FoodEventArg e) {
Console.WriteLine("{0} receives {1}",name,e.getFood());
}
}
class Dealer {
public event myEventHandle FoodInfo;
public void Receive(string food) {
Console.WriteLine("Dealer: food->{0}",food);
RaiseEvent(food);
}
protected void RaiseEvent(string food) {
FoodInfo?.Invoke(this, new FoodEventArg(food));
}
}
class EventTest {
static void Main() {
Dealer _dealer = new Dealer();
Person _personA = new Person("Evan");
Person _personB = new Person("Cathy");
_dealer.FoodInfo += _personA.FoodRecive;
_dealer.Receive("Rice");
_dealer.FoodInfo += _personB.FoodRecive;
_dealer.Receive("Potato");
_dealer.FoodInfo -= _personA.FoodRecive;
_dealer.Receive("Cucumber");
}
}
}

  使用Dealer的FoodInfo事件,通过“+=”来注册一个订阅(实质上就是把一个事件添加到事件队列当中),通过“-=”来取消一个订阅。

  例子中食物(Food)的接收一个事件参数,当一个食物被接收时,查看有多少用户订阅该事件可以接收到该食物,一开始只有Even订阅了事件,所以Even接收到了Rice,然后Cathy注册了订阅,所以Even和Cathy(队列结构)依次接收到了Potato,随后Even取消了订阅,所以后来的Cucumber只有当前注册订阅用户Cathy能够接收。

  懒得手写运行结果,以下贴出运行结果图:

  

  通过这个例子能够比较清楚地明白C#事件当中 事件执行 者和 事件参数 的作用,C#事件是一种新的类型处理方式,同时更是一种设计模式。

  声明:以上 C#编程语言之委托与事件(一)和 C#编程语言之委托与事件(二)均由本人原创编写,文中的每一处代码均经过本人亲自测试能够按照文中所述的结果呈现,如果问题,请及时告知。

  文章引用:

  1、http://www.cnblogs.com/xlx0210/archive/2010/08/08/1794959.html

  尊重知识产权,争取共同进步!

C#编程语言之委托与事件(二)—— C#事件的更多相关文章

  1. C#特性知识图谱-二、事件

    C#特性知识图谱-二.事件 二.事件 在事件驱动的软件系统中,符合某种预设条件的情形出现是,一个事件就会被触发. 2.1 事件三要素 事件源:激发事件的对象 事件信息:事件本身说携带的信息 事件响应者 ...

  2. javaScript事件(二)事件处理程序

    一.事件 二.事件流 以上内容见:javaScript事件(一)事件流 三.事件处理程序 前面提到,事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字.响应 ...

  3. 解密jQuery事件核心 - 委托设计(二)

    第一篇 http://www.cnblogs.com/aaronjs/p/3444874.html 从上章就能得出几个信息: 事件信息都存储在数据缓存中 对于没有特殊事件特有监听方法和普通事件都用ad ...

  4. Javascript事件模型系列(二)事件的捕获-冒泡机制及事件委托机制

    一.事件的捕获与冒泡 由W3C规定的DOM2标准中,一次事件的完整过程包括三步:捕获→执行目标元素的监听函数→冒泡,在捕获和冒泡阶段,会依次检查途径的每个节点,如果该节点注册了相应的监听函数,则执行监 ...

  5. .NET Core 跨平台物联网开发:设置委托事件(二)

    系列教程目录 (一) 连接阿里云IOT (二) 设置委托事件 (三) 上报属性 (四)  SDK文档 属性.方法.委托.类 http://pan.whuanle.cn/index.php?dir=up ...

  6. C++模拟C#事件委托机制(二)

    原文 来自于http://www.cnblogs.com/netssfy/archive/2010/02/02/1662056.html 为了解决非法地址访问的冲突,首先需要知道发生该错误的原因是什么 ...

  7. HTML 事件(二) 事件的注册与注销

    本篇主要介绍HTML元素事件的注册.注销的方式. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流.事件委托 4. ...

  8. HTML 事件(三) 事件流与事件委托

    本篇主要介绍HTML DOM中的事件流和事件委托. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流与事件委托 4 ...

  9. js事件捕获,事件冒泡,事件委托以及DOM事件流

    一:DOM事件流: 事件流是从页面接收事件的顺序,DOM2级事件规定事件流包括三个阶段: ①事件捕获阶段:用意在于事件达到目标之前捕获它,在事件捕获阶段事件流模型:document→html→body ...

随机推荐

  1. dojo加载树报错

    1.错误描述    error loading undefined children.    TypeError:this._arrayOfTopLevelItems is undefied. 2.错 ...

  2. hihocoder Challenge 29 B.快速乘法

    这题的题解和我写的有一拼,异常简洁,爆炸. 这题思路dp 表示的是讨论到第位,并比原数的前n位多了 显然j只能取0,1,毕竟2进制嘛 之后转移就好了,注意下面两个重要状态 #include <c ...

  3. pat1061-1070

    1061 我想吐槽这题的题意不够清楚,不过下次得长记性,对于模糊的题意要大胆猜测,而不是固执己见 #include<iostream> #include<cstdio> #in ...

  4. linux和windows通用的路径

    String path=request.getSession().getServletContext().getRealPath("/")+"js" + Sys ...

  5. SqlBulkCopy 批量复制数据到数据库

    1.简介 1.MSDN 核心方法:SqlBulkCopy.WriteToServer 将所有行从数据源复制到 SqlBulkCopy 对象的 DestinationTableName 属性指定的目标表 ...

  6. 爬虫工具fiddle在firefox浏览器中的使用

    1.fiddle工作原理 浏览器与服务器之间通过建立TCP连接以HTTP协议进行通信,默认通过自己发送HTTP(或HTTPS)请求到服务器. 使用Fiddler之后,浏览器像目标服务器发送的请求都会经 ...

  7. 创建文本节点createTextNode

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  8. js去重合并

    1.去重 for(var q = 0;q<jsonArr.length;q++){   for(var e=0;e<jsonArr[q].data.length;e++){   var m ...

  9. python中的小知识点

    这里是一些小知识点的汇集,为的是以后查找的方便. 行与缩进: 物理行:实际看到的代码行数. 逻辑行:在意义上的函数(即解释器执行的行数) 如果一个物理行中包含了多个逻辑行,则每个逻辑行之间需要用分号 ...

  10. JavaScript的基本操作(一)

    JavaScript中有大量的方法可供我们使用,详情可参考:http://jquery.cuishifeng.cn/这也同时导致我们不可能去记住每一个的用法,且开发者每天都在新添更多的方法,所以要想掌 ...