前面已经大致讲述了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. 快速开发 HTML5 交互式地铁线路图

    前言 前两天在 echarts 上寻找灵感的时候,看到了很多有关地图类似的例子,地图定位等等,但是好像就是没有地铁线路图,就自己花了一些时间捣鼓出来了这个交互式地铁线路图的 Demo,地铁线路上的点是 ...

  2. window.load 和$(document).ready() 区别

    1.执行时间 window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行. $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕.2.编写个数不同 w ...

  3. javscript eval()的优缺点与web安全防范

    要说JavaScript中最为强大的一个方法便是eval()方法呢,为何如此说呢?因为它就像是一个JavaScript解析器,也就是说它的参数就是一段js代码所构成的字符串,当执行这个函数的时候,会把 ...

  4. js常见排序

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  5. [NOIP2017] 逛公园

    [NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^ ...

  6. 【ZJOI2008】树的统计(树链剖分)

    题面 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II ...

  7. Docker_快速部署jenkins

    开门见山,如何在利用docker快速部署jenkins服务?下面详解 1:docker的基本按照与部署,前文已经详述,这里不多说. 2:pull一个jenkins镜像 docker pull jenk ...

  8. 论文笔记(3):STC: A Simple to Complex Framework for Weakly-supervised Semantic Segmentation

    论文题目是STC,即Simple to Complex的一个框架,使用弱标签(image label)来解决密集估计(语义分割)问题. 2014年末以来,半监督的语义分割层出不穷,究其原因还是因为pi ...

  9. TypeScript入门知识四(表达式和循环)

    一,箭头表达式 用来声明匿名函数,消除传统匿名函数的this指针问题 //单行的话可以省略{},多行的不能省. var sum = (arg1,arg2)=> arg1+arg2; //定义一个 ...

  10. 从头编写asp.net core 2.0 web api 基础框架 (5) + 使用Identity Server 4建立Authorization Server (7) 可运行前后台源码

    前台使用angular 5, 后台是asp.net core 2.0 web api + identity server 4. 从头编写asp.net core 2.0 web api 基础框架: 第 ...