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

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

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

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

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

  1. private void button1_Click(object sender, EventArgs e) {}
  1. 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点击事件来深入了解:

  1. using System;
  2. namespace ConsoleApplication {
  3. //(1)定义一个delegate对象类型
  4. delegate void myEventHandle(object sender, EventArgs e);
  5. class MyEventArg : EventArgs {
  6. //(2)定义事件类,应派生于EventArgs类
  7. public string EventArgsName() {
  8. return "[MyEventArgsName]";
  9. }
  10. }
  11. class _Button {
  12. //(4)定义事件对象,注意关键字和类型
  13. public event myEventHandle Click;
  14. protected void OnUtilEvent(MyEventArg e) {
  15. if(null != Click) {
  16. Click(this, e);
  17. }
  18. }
  19. public void RaiseEvent() {
  20. MyEventArg e = new MyEventArg();
  21. OnUtilEvent(e);
  22. }
  23. public string ButtonName() {
  24. return "[myButtonName]";
  25. }
  26. }
  27. class EventTest {
  28. //(3)定义事件处理方法,保证函数列表和返回值的有效性
  29. static void _Button_Click(object sender, EventArgs e) {
  30. Console.WriteLine("\nYou have clicked the button");
  31. Console.WriteLine("The eventObject is :\t"+(sender as _Button).ButtonName());
  32. Console.WriteLine("The eventArgs is:\t"+(e as MyEventArg).EventArgsName());
  33. }
  34. static void Main() {
  35. _Button _button = new _Button();
  36. //(5)用操作符把事件添加到事件队列当中
  37. _button.Click += new myEventHandle(_Button_Click);
  38. Console.Write("Do you want to click the button(Y/N)");
  39. if (Console.ReadKey().KeyChar == 'Y')
  40. _button.RaiseEvent();
  41. else
  42. Console.WriteLine("The event does not raise");
  43. }
  44. }
  45. }

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

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

  事件发布器:

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

  1. using System;
  2. namespace ConsoleApplication {
  3. public delegate void myEventHandle(object sender,FoodEventArg e);
  4. public class FoodEventArg : EventArgs {
  5. private string food;
  6. public FoodEventArg(string food) {
  7. this.food = food;
  8. }
  9. public string getFood() {
  10. return food;
  11. }
  12. }
  13. class Person {
  14. private string name;
  15. public Person(string name) {
  16. this.name = name;
  17. }
  18. public void FoodRecive(object sender,FoodEventArg e) {
  19. Console.WriteLine("{0} receives {1}",name,e.getFood());
  20. }
  21. }
  22. class Dealer {
  23. public event myEventHandle FoodInfo;
  24. public void Receive(string food) {
  25. Console.WriteLine("Dealer: food->{0}",food);
  26. RaiseEvent(food);
  27. }
  28. protected void RaiseEvent(string food) {
  29. FoodInfo?.Invoke(this, new FoodEventArg(food));
  30. }
  31. }
  32. class EventTest {
  33. static void Main() {
  34. Dealer _dealer = new Dealer();
  35. Person _personA = new Person("Evan");
  36. Person _personB = new Person("Cathy");
  37. _dealer.FoodInfo += _personA.FoodRecive;
  38. _dealer.Receive("Rice");
  39. _dealer.FoodInfo += _personB.FoodRecive;
  40. _dealer.Receive("Potato");
  41. _dealer.FoodInfo -= _personA.FoodRecive;
  42. _dealer.Receive("Cucumber");
  43. }
  44. }
  45. }

  使用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. httpclient的get带参不带参post带参不带参的简单应用

    一,基础的的应用 1.1,get的无参请求 @Test public void doGet() throws Exception { //创建一个httpclient对象 CloseableHttpC ...

  2. 手机端仿ios的1-n级联动脚本二

    一,图片 二,代码 2.1,html脚本 var weekdayArr=['周日','周一','周二','周三','周四','周五','周六'];var timeArr = ['08:30','09: ...

  3. 动态链接库(DLL)

    DLL 的类型 当您在应用程序中加载 DLL 时,可以使用两种链接方法来调用导出的 DLL 函数.这两种链接方法是加载时动态链接和运行时动态链接. 加载时动态链接 在加载时动态链接中,应用程序像调用本 ...

  4. R语言学习 第七篇:列表

    列表(List)是R中最复杂的数据类型,一般来说,列表是数据对象的有序集合,但是,列表的各个元素(item)的数据类型可以不同,每个元素的长度可以不同,是R中最灵活的数据类型.列表项可以是列表类型,因 ...

  5. Spring 之BeanFactory(转)

    BeanFactory是Spring的“心脏”.它就是Spring IoC容器的真面目. Spring使用BeanFactory来实例化.配置和管理Bean.但是,在大多数情况我们并不直接使用Bean ...

  6. HTTP的长连接,你不知道的连接。。。

    长连接起源 什么样的连接才能称之为长连接?要多长.... http是一种无状态的协议,也就是stateless协议,而http协议又是建立在tcp/ip协议的基础之上的. 无状态表示每次请求都是一次独 ...

  7. 【CF235C】Cyclical Quest(后缀自动机)

    [CF235C]Cyclical Quest(后缀自动机) 题面 洛谷 题解 大致翻译: 给定一个串 然后若干组询问 每次也给定一个串 这个串可以旋转(就是把最后一位丢到最前面这样子) 问这个串以及其 ...

  8. 【BZOJ4407】于神之怒加强版(莫比乌斯反演)

    [BZOJ4407]于神之怒加强版(莫比乌斯反演) 题面 BZOJ 求: \[\sum_{i=1}^n\sum_{j=1}^mgcd(i,j)^k\] 题解 根据惯用套路 把公约数提出来 \[\sum ...

  9. 【HDU2255】奔小康赚大钱

    题面 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓 ...

  10. app图标icon大全

    http://tool.58pic.com/tubiaobao/index.php?m=Index&a=ui&p=2 很有用,下载没用,直接右键吧.