什么是事件
事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些 提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。
C#中使用事件机制实现线程间的通信。
事件的处理需要委托实现来调度事件,所以事件和委托是紧密关联的(耦合性高)
通过事件使用委托
事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。 包含事件的类用于发布事件。这被称为 发布器(publisher) 类。其他接受该事件的类 被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。
发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义 在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。
订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher) 类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。
简单来说就是事件可以为任何一种委托类型提供一种发布/订阅机制。用户可以订阅这 个事件,当发布者触发事件后,所有的订阅者都会收到通知。关键是发布者不知道订阅 者是谁,有多少个订阅者。这样的好处是各个模块可以专心做自己的事,不需要过问其 他模块的事情。
声明事件步骤
在类的内部声明事件,首先必须声明该事件的委托类型。例如:
public delegate void PrintHandler();
其次,使用 event 关键字声明事件本身:
public event PrintHandler printTest;
上面的代码定义了一个名为 PrintHandler的委托和一个名为 PrintTest 的事件,该事件在生成的时候会调用委托。
然后调用事件,但是只能在声明事件的类中调用事件
If(printTest!=null)
printTest();
或者
printTest?.Invoke();
这个代码就是判断printTest是否为空,不为空就调用printTest()方法,为空就不执行
最后注册事件,这里声明事件的类为Sample类
Sample.printTest+=实例方法/静态方法
取消订阅的话用-=即可
下面用一段代码演示:
using System;
namespace ConsoleApp1
{
//发布器类
public class Sample
{
//声明委托
public delegate void OrderEventHandler(int x);
//声明事件
public event OrderEventHandler order;
//调用事件
protected virtual void OnCall()
{
order?.Invoke(99);
}
public void Start()
{
OnCall();
}
}
//订阅器类-1
public class SubscribEvent1
{
public void Print(int x)
{
Console.WriteLine("订阅器1,打印数字:"+x);
}
}
//订阅器类-2
public class SubscribEvent2
{
public void Print(int x)
{
Console.WriteLine("订阅器2,打印数字:"+x);
}
}
class Program
{
static void Main(string[] args)
{
//实例化对象-订阅器类
SubscribEvent1 se1 = new SubscribEvent1();
SubscribEvent2 se2 = new SubscribEvent2();
//实例化对象-发布器类
Sample sample = new Sample();
//订阅
sample.order += se1.Print;
sample.order += se2.Print;
//调用事件
sample.Start();
Console.ReadLine();
}
}
}
输出结果:
订阅器1,打印数字:99
订阅器2,打印数字:99
上面我们用发布器类的start函数来调用Oncall函数引发一个事件。通常要引发事件, 应该使名称定义受保护的虚拟方法,protected和virtual使派生类能够覆盖引发事件的 逻辑,但是派生类要始终调用这个受保护的方法,以确保注册的委托接收事件
我们+=来订阅事件,这里订阅了两个方法,当调用事件时这两个方法都会调用
内置 EventHandler 委托
系统内置了两个常用的委托类型 EventHandler 和 EventHandler<TEventArgs> 。通常, 任何事件都应包括两个参数:事件源和事件数据。EventHandler 主要用于不包含事件数 据;对包含事件数据的使用 EventHandler<TEventArgs>
如有错漏之处,敬请指正!