浅析C#中的事件
讲过了委托,不得不讲事件。
事件基于委托,为委托提供了一种发布/订阅机制。
在发生其他类或对象关注的事情时,类或对象可通过事件通知它们。发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”。
在典型的 C# Windows 窗体或 Web 应用程序中,可订阅由控件(如按钮和列表框)引发的事件。可使用 Visual C# 集成开发环境 (IDE) 来浏览控件发布的事件,选择要处理的事件。IDE 会自动添加空事件处理程序方法和订阅事件的代码。
事件时对委托的封装。
事件帮助解决委托封装问题。事件位于委托的顶部,并提供封装,使得目标源只能听而不能完全控制的委托对象。
下图显示了事件的样子: -

理解事件:
Button是一个类,当你点击按钮的时候,Click事件被触发。
定时器是一个类,每毫秒tick事件被触发。
下面通过一个例子来讲述一下事件的应用。
定义两个类CarDealer和Consumer。CarDealer类提供了一个新车到达时触发的事件,Consumer类订阅该事件,以获得新车到达的通知。
事件发布程序:CarDealer类提供了EventHandler类型的NewCarInfo事件。事件一般使用带两个参数的方法。第一个参数是一个对象,包含事件的发送者;第二个参数提供了事件的相关信息。
你可能感到吃惊,没有定义委托怎么就定义事件了??其实有了泛型委托EventHandler 委托后,就不再需要委托了。
EventHandler 的语法如下:
public delegate void EventHandler(Object sender,TEventArgs e) where TEventArgs : EventArgs
EventHandler定义了一个处理程序,返回void,接受两个参数。第一个参数必须是object,第二个参数是T类型,对于T有一个约束,就是它必须派生自基类EventArgs。下面代码的CarInfoEventArgs就派生自基类EventArgs.
EventArgs是包含事件数据的类的基类,此类不包含事件数据,在事件引发时不向事件处理程序传递状态信息的事件会使用此类。如果事件处理程序需要状态信息,则应用程序必须从此类派生一个类来保存数据。事件处理程序委托的标准签名定义一个没有返回值的方法,其第一个参数的类型为 Object,它引用引发事件的实例,第二个参数从 EventArgs 类型派生,它保存事件数据。 如果事件不生成事件数据,则第二个参数只是 EventArgs 的一个实例。 否则,第二个参数为从 EventArgs 派生的自定义类型,提供保存事件数据所需的全部字段或属性。
EventHandler 是一种预定义委托,表示事件的事件处理程序方法,它与事件是否生成事件数据无关。 如果事件不生成事件数据,则用 EventArgs 替代泛型类型参数;否则,提供自己的自定义事件数据类型并用该类型替代泛型类型参数。
使用 EventHandler 的优点在于,如果事件生成事件数据,则无需编写自己的自定义委托代码。 此外,.NET Framework 只需一个实现就能支持 EventHandler ,这与替代泛型类型参数的事件数据类型无关。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestEvent
{
public class CarInfoEventArgs:EventArgs
{
public CarInfoEventArgs(string car)
{
this.Car = car;
}
public string Car{get; private set;}
}
public class CarDealer
{
public event EventHandlerNewCarInfo;
public void NewCar(string car)
{
Console.WriteLine("CarDealer. new car {0}", car);
if (NewCarInfo != null)
{
NewCarInfo(this, new CarInfoEventArgs(car));
}
}
}
}
事件监听器:Consumer类用作事件侦听器。这个类订阅了CarDealer类的事件,并定义了NewCarIsHere方法,该方法满足EventHandler委托的要求,其参数类型是object和CarInfoEventArgs.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestEvent
{
class Consumer
{
private string name;
public Consumer(string name)
{
this.name = name;
}
public void NewCarIsHere(object sender, CarInfoEventArgs e)
{
Console.WriteLine("{0}: car {1} is new", name, e.Car);
}
}
}
现在需要连接事件发布器和订阅器。使用“+=”创建一个订阅。使用“-=”取消了订阅。使用代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestEvent
{
class Program
{
static void Main(string[] args)
{
var dealer = new CarDealer();
var michael = new Consumer("Michael");
dealer.NewCarInfo += michael.NewCarIsHere;
dealer.NewCar("Mercedes");
var nick = new Consumer("Nick");
dealer.NewCarInfo += nick.NewCarIsHere;
dealer.NewCar("Ferrari");
dealer.NewCarInfo -= michael.NewCarIsHere;
dealer.NewCar("Toyota");
}
}
}
/*-------------------------------------
输出结果:
CarDealer. new car Mercedes
Michael: car Mercedes is new
CarDealer. new car Ferrari
Michael: car Ferrari is new
Nick: car Ferrari is new
CarDealer. new car Toyota
Nick: car Toyota is new
---------------------------------------*/
https://www.cnblogs.com/sjqq/p/6918006.html
浅析C#中的事件的更多相关文章
- 浅析 JavaScript 中的 函数 currying 柯里化
原文:浅析 JavaScript 中的 函数 currying 柯里化 何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字 ...
- 浅析 Linux 中的时间编程和实现原理一—— Linux 应用层的时间编程【转】
本文转载自:http://www.cnblogs.com/qingchen1984/p/7007631.html 本篇文章主要介绍了"浅析 Linux 中的时间编程和实现原理一—— Linu ...
- 深入浅析python中的多进程、多线程、协程
深入浅析python中的多进程.多线程.协程 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源 ...
- C++中的事件分发
本文意在展现一个C++实现的通用事件分发系统,能够灵活的处理各种事件.对于事件处理函数的注册,希望既能注册到普通函数,注册到事件处理类,也能注册到任意类的成员函数.这样在游戏客户端的逻辑处理中,可以非 ...
- javascript中的事件冒泡和事件捕获
1.事件冒泡 IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档).以下面的HTML ...
- jQuery文本框中的事件应用
jQuery文本框中的事件应用 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...
- 怎么理解js中的事件委托
怎么理解js中的事件委托 时间 2015-01-15 00:59:59 SegmentFault 原文 http://segmentfault.com/blog/sunchengli/119000 ...
- jQuery中的事件绑定方法
在jQuery中,事件绑定方法大致有四种:bind(),live(), delegate(),和on(). 那么在工作中应该如何选择呢?首先要了解四种方法的区别和各自的特点. 在了解这些之前,首先要知 ...
- 四、jquery中的事件与应用
当用户浏览页面时,浏览器会对页面代码进行解释或编译--这个过程实质上是通过时间来驱动的,即页面在加载时,执行一个Load事件,在这个事件中实现浏览器编译页面代码的过程.时间无论在页面元素本身还是在元素 ...
随机推荐
- UOJ136 开学前的作文
描述 红包是一个萌萌的男孩子. 红包由于 NOI 惨挂,直到前不久依然无心写作业.如今快开学了,他决定好好完成作业. 对于可以交电子稿的作文,红包有特殊的完成技巧,大致流程是依次选中一段内容→按下 C ...
- linux学习-环境变量与文件查找
- 翻译Lanlet2
Here is more information on the basic primitives that make up a Lanelet2 map. Read here for a primer ...
- php/js/linux: js加密(rsa公钥加密) php解密(rsa私钥解密)
php/js/linux: js加密(rsa公钥加密) php解密(rsa私钥解密) 一: js rsa 插件 https://github.com/UFO0001/WX_RSA 或者: https: ...
- 【DP专辑】ACM动态规划总结(转)
http://blog.csdn.net/cc_again/article/details/25866971 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间效率高,代码量少,多元性强, ...
- Selenium-几种等待方式
强制等待 一直使用的time.sleep(5),可以放在任意地方,不好的地方,不太准确确定时间 隐形等待 driver.implicitly_wait(5) 设置了一个最长等待时间,如果在规定时间内网 ...
- 6 Python 数据类型—字符串
字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可. var1 = 'Hello World!' var2 = ...
- L105
A pill could soon radio signals from inside your gut to help doctors diagnose diseases from ulcers t ...
- Android数据传递的五种方法汇总
Android开发中,在不同模块(如Activity)间经常会有各种各样的数据需要相互传递,我把常用的几种 方法都收集到了一起.它们各有利弊,有各自的应用场景. 我现在把它们集中到一个例子中展示,在例 ...
- Bootstrap日期/日历插件Datepicker 时间加标记
由于工作需要,项目中使用了Bootstrap日期/日历插件Datepicker,根据需求需要在其中添加日期标记,实现效果图如下: 特此记录此次解决方案: 1.首先分析了功能的DOM元素(如下图),可以 ...