1:什么是事件?
在文档是这样定义的,事件就是一种使对象或者类能够提供通知的的成员,就是对象或者类具备了通知的能力。(闹钟响了给起床了这个事件告诉我们 谁通知了这个事件(闹钟)通知了谁(我)闹钟响了我该干什么(起床))
2下面是一些关于事件的重要事项
发布者:意思就是发布某一个事件的类或者是结构,其他类可以在该事件发生时得到通知
订阅者:注册并在事件发生时得到通知类或者是结构。
事件处理程序(event handler):由订阅者注册到事件中的方法,在发布者触发事件时执行。事件处理程序方法可以定义在事件所在的类中或者是结构中,也可以在不同的类或者结构中。
*其实事件和委托是非常相似的,实际上事件就像专门用于某种特殊的用途的简单委托,事件包含了一个私有的委托,委托中又几个方法。
*有关事件的私有委托重要事项如下:
事件提供了对他的私有控制委托的结构的访问。也就是说你没有办法直接访问(可以这样说就是事件就是安全版的委托)
事件中可以用的操作比委托少,对于事件我们只可以添加,删除或者调用事件处理程序
当事件被触发时候,事件调用委托依次来调用委托中的方法
3:源代码组件概览
事件中使用的代码是由5部分组成的,下面对这些组件一一进行介绍
委托类型的声明:事件和事件处理程序必须有相同的签名和返回值,他们通过委托类型进行描述
事件处理程序声明: 订阅者类中会在事件触发时执行的方法声明。他们不一定是显示命名的方法,还可以是匿名方法和Lambda表达式
事件声明: 发布者类中必须声明一个订阅者类可以注册的事件成员。当声明的事件为publi时,称为发布了事件。
事件注册: 订阅者必须订阅事件,才能在事件触发时得到通知。
触发事件的代码:发布者类中“触发”事件并导致调用注册的所有事件处理程序的代码。
4:声明事件
发布者必须提供事件对象。
事件声明在一个类中
它需要委托类型的名称,任何附加到事件的处理程序都必须与委托类型的签名和返回值相匹配,
它声明为public,这样其他类和结构可以在它上面注册事件处理程序
不能使用对象创建表达式(new 表达式)来创建它的对象
class Incrementer{
Public event EventHandle CountedADozen;
}
//event关键字
//EventHandle委托类型
//CountedADozen事件名
如果有多个事件需要声明(使用逗号分开各个事件)
class Incrementer{
Public event EventHandle CountedADozen,MyEvent1,MyEvent2;
}
我们还可以将事件声明为static静态的
class Incrementer{
Public static event EventHandle CountedADozen;
}
5:订阅事件
订阅者向事件添加事件处理程序。对于一个要添加到事件的事件处理程序来说,他必须要具有与事件委托相同的返回值类型和签名
使用+=运算符来为事件增加事件处理程序,
事件处理程序的规范可以是以下任意一种
实例方法发名称
静态方法的名称
匿名方法
Lambda表达式
举例:
Incrementer.CounteAdozen+=IncrementerDozensCount;//引用形式实例方法
Incrementer。counteADzzen+=ClassB.CounterHandler;//引用形式静态方法
mc.CountedADozen+=new EventHandleer(cc.CounterHandlerc);//委托形式
Incrementer.CounteAdozen+=delegate{DozensCount++;};//匿名方法
Incrementer.CounteAdozen+=()>=DozensCount;//lambdda表达式
6触发事件
事件成员本身只是保存了需要被调用的事件处理程序。如果事件没有触发,什么都不会发生。
例如:
在触发事件之前和null进行比较,从而查看否包含书记兼处理程序,如果是null,则表示没有,不能执行。
触发事件的语法和调用方法一样;
使用事件名称,后面跟的参数列表包含在圆括号中;
参数列表必须与事件的委托类型相匹配
if(countedADozen!=null)//确定方法可执行
CountedADozen(source,ages)//触发事件
//CountedADozen事件名
把事件的声明和触发事件的代码放在一起就成如下;
class Incrementer{
public event Eventhandeler CountedADzen;//声明事件
void Docount(Object souce,EventArgs args){
for(int i=1; i<100; i++){
if(i%12==0&&CountedADozen!=null){
CountedADozen(source,args);//触发事件
}
}
}
}
说了这么多咋们该把前面的的铺垫总结在一起了,就是订阅者和发布者事件处理程序。
第一步申明委托:
delegate void Handler();
第二步创建发布者类(里面包括事件的声明和事件的触发)
class Incrementer{
public event Handler CountedADozen;//创建事件并发布
public void DoCount(){
//事件是按照什么逻辑触发
for(int i=0;i<100;++){
if(i%12==0&&CountedADozen!=null){
//如果满足条件了我就让事件触发
CountedADozen();
}
}
}
}
第三步创建订阅者类
class Dozens{
public int DozensCount{get;set;}
public Dzens(Incrementer incrementer){
DozensCount=o;
//订阅事件
incrementer.CountedADozen+=IncrementDozensCount;
//声明事件处理程序
void IncrementDozensCount()
{
DozensCount++
}
}
}
运行结果类
class Program{
//初始化订阅者类和发布者类
Incrementer incrementer=new Incrementer();
Dozens dozensCounter=new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number f dozens {0}",dozensCounter.DozensCount);
}
就像我开头举的例子(我昨天订了今天8点起床的闹钟)这就是一个事件发布者就是手机闹钟,订阅者就是我,事件处理程序就是起床,事件注册(订阅事件)就是我前一天晚上在手机上订闹钟啊,触发事件的代码就8点这个时间点。
7:标准事件
.NET框架提供的一个标准模式,事件使用的标准模式根本就是system命名空间声明的EventHandler委托类型。关于EventHaandler委托类型的声明注意以下几点
第一个参数是为了保存事件的引用,所以是Object类型的,是所有类型基类
第一个参数是用来保存状态信息,指明什么类型适用于该应用程序
返回值为void
public delegate void EventHandler(Object sender ,EvenArgs e);
我们在使用系统的委托类型时注意什么?
在声明使用系统定义的EventHandler委托替换Handler
订阅者中声明的事件处理程序的签名与必须事件委托的签名匹配
触发事件的代码在调用事件时必须使用适当的参数类型的对象
例如:
发布者类
class Incrementer{
public event EventHandler CountedADozen;//使用系统定义的委托
public void DoCount(){
//事件是按照什么逻辑触发
for(int i=0;i<100;++){
if(i%12==0&&CountedADozen!=null){
//如果满足条件了我就让事件触发
CountedADozen(this,null);
}
}
}
}
订阅者类
class Dozens{
public int DozensCount{get;set;}
public Dzens(Incrementer incrementer){
DozensCount=o;
//订阅事件
incrementer.CountedADozen+=IncrementDozensCount;
//声明事件处理程序
void IncrementDozensCount(Object sender ,EvenArgs e)//事件处理程序的签名必须与委托签名匹配
{
DozensCount++
}
}
}
运行结果类
class Program{
//初始化订阅者类和发布者类
Incrementer incrementer=new Incrementer();
Dozens dozensCounter=new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number f dozens {0}",dozensCounter.DozensCount);
}
上面说EventArgs参数是用来传递参数的,我,我们是不是就可以传递一些参数呢?答案是不能的
那么我们怎么才能传递数据呢?
我们可以创建一个派生自EventArgs类自定义类
public class IncrementEventerArgs:EventArgs
{
public int IterationCount{get;set;}
}
现在我们有一个新定义的类,就可以对数据进行传参数了,但是我们现在需要一个泛型 的委托EeventHandler<>
public event EventHandler<IncrementEventerArgs> countedADozen;
那么我想知道上面的每一个12的倍数的的逻辑就是
public class IncrementEventerArgs:EventArgs
{
public int IterationCount{get;set;}
}
delegate void EventHandler<IncrementEventerArgs>();//声明委托类型
//发布者类
class Incrementer{
public event EventHandler<IncrementEventerArgs>() CountedADozen;//使用系统定义的委托
public void DoCount(){
//自定义类对象
IncrementEventerArgs args=new IncrementEventerArgs();
//事件是按照什么逻辑触发
for(int i=0;i<100;++){
if(i%12==0&&CountedADozen!=null){
//如果满足条件了我就让事件触发
args.IterationCount=i;
CountedADozen(this,agrs);
}
}
}
//订阅者类
class Dozens{
public int DozensCount{get;set;}
public Dzens(Incrementer incrementer){
DozensCount=o;
//订阅事件
incrementer.CountedADozen+=IncrementDozensCount;
//声明事件处理程序
void IncrementDozensCount(Object sender ,IncrementEventerArgs e)//事件处理程序必须要与委托签名一样
{
Console.WriteLine(e.IterationCount,sender.Tostring());
DozensCount++
}
}
}
class Program{
//初始化订阅者类和发布者类
Incrementer incrementer=new Incrementer();
Dozens dozensCounter=new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number f dozens {0}",dozensCounter.DozensCount);
}