事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。
C# 中使用事件机制实现线程间的通信。
事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件。这被称为 发布器 类。其他接受该事件的类被称为 订阅器 类。事件使用 发布-订阅 模型。
发布器 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器类的对象调用这个事件,并通知其他的对象。
订阅器 是一个接受事件并提供事件处理程序的对象。在发布器类中的委托调用订阅器类中的方法(事件处理程序)。
声明事件
在类的内部声明事件,首先必须声明该事件的委托类型。
public delegate void LogHandler(string status);
然后,声明事件本身,使用 event 关键字:
// 基于上面的委托定义事件
public event LogHandler EventLog;
//上面的代码定义了一个名为 LogHandler 的委托和一个名为 EventLog 的事件,该事件在生成的时候会调用委托。
实例:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
/***********发布器类***********/
public class EventPublisher
{
private int value;
public delegate void NumManipulationHandler();
public event NumManipulationHandler ChangeNum;
protected virtual void OnNumChanged()
{
if (ChangeNum != null)
{
ChangeNum(); /* 事件被触发 */
}
else
{
Console.WriteLine("event not Commit");
Console.ReadKey(); /* 回车继续 */
}
}
public EventPublisher()
{
int n = 5;
SetValue(n);
}
public void SetValue(int n)
{
if (value != n)
{
value = n;
OnNumChanged();
}
}
}
/***********订阅器类***********/
public class EventSubscrib
{
public void printf()
{
Console.WriteLine("event Commit");
Console.ReadKey(); /* 回车继续 */
}
}
/***********触发***********/
static void Main(string[] args)
{
EventPublisher e = new EventPublisher(); /* 实例化对象,第一次没有触发事件 */
EventSubscrib v = new EventSubscrib(); /* 实例化对象 */
e.ChangeNum += new EventPublisher.NumManipulationHandler(v.printf); /* 注册 */
e.SetValue(7);
e.SetValue(11);
Console.ReadKey();
}
}
}
实例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BoilerEvent_tz
{
class DelegateTest
{
public delegate void delegate_tz();
public event delegate_tz delegate_tz0;
public void start()
{
Console.WriteLine("启动事件");
delegate_tz0(); // 得调用该事件呀
Console.ReadKey();
}
}
class Program
{
static void Main(string[] args)
{
DelegateTest DelegateTest0 = new DelegateTest();
//DelegateTest0.delegate_tz0 += DelegateTest.delegate_tz(test); // 必须new一下才行,因为它是另外一个类呀
DelegateTest0.delegate_tz0 += new DelegateTest.delegate_tz(test);
DelegateTest0.start(); // 启动事件
}
static public void test()
{
Console.WriteLine("这是一个被注册的函数,按任意键继续...");
Console.ReadKey();
}
}
}
delegate 相当于定义一个函数类型。
event 相当于定义一个 delegate 的函数指针(回调函数指针)。
事件的整个过程是:订阅 -> 发布 -> 执行。
- 订阅: 假设事件 A 的执行方法是 F_A,事件 B 的执行方法是 F_B,将这些事件与它们的委托人进行绑的行为就是订阅,这个委托人就是发布器的一个成员。订阅器另一个行为就是在订阅之后(必学先订阅)通知发布器的相关成员。
- 发布: 首先要明确事件发布的类型(由事件的执行方法参数列表决定)和要发布事件的变量(这个变量即委托人);其次整理发布所需的材料、判断条件是否合适等;最后让内部的委托人向执行函数传递最终信息。
- 执行: 是整个事件最后完成的步骤,就是普通的函数。
委托是一个类,事件则是委托类中的一个对象,该对象是能够把其他方法注册到委托类中的一个事件
事件和函数的关系:事件具有可以注册多个函数(和解绑函数)的功能,而函数如果要注册和解绑其他在其主体上运行的函数则需要改动该函数本体的代码,这就是区别。
using System;
namespace DelegateAndEvent
{
//定义一个事件类
public class MyEvent
{
//定义一个委托
public delegate void MyDelegate();
//定义一个事件
public MyDelegate MyDelegateEvent;
//定义一个触发事件的函数
public void OnMyDelegateEvent()
{
//判断事件是否非空
if (MyDelegateEvent != null)
{
//执行事件
MyDelegateEvent();
}
//MyDelegateEvent?.Invoke(); //简化的判断和执行
}
}
class Program
{
//输出一串字符
public static void putOutChar()
{
Console.WriteLine("I was fired");
}
//输出第二串字符
public static void putOutChar2()
{
Console.WriteLine("I was fired22222");
}
static void Main(string[] args)
{
//实例化MyEvent2类
MyEvent myEvent = new MyEvent();
//注册一个事件
myEvent.MyDelegateEvent += new MyEvent.MyDelegate(putOutChar);
myEvent.MyDelegateEvent += new MyEvent.MyDelegate(putOutChar2);
//执行触发事件的函数
Console.WriteLine("执行绑定了两个事件后的函数");
myEvent.OnMyDelegateEvent();
//解绑一个事件
myEvent.MyDelegateEvent -= new MyEvent.MyDelegate(putOutChar);
//再次执行触发事件的函数
Console.WriteLine("执行解绑了一个事件后的函数");
myEvent.OnMyDelegateEvent();
Console.ReadKey();
}
}
}
以上代码过程:定义一个新类(事件类)--》类中声明委托--》由委托类又声明事件--》再定义触发事件的函数--》函数主体中执行事件--》在主函数中实例化事件类--》进而调用事件类中的事件对象--》事件对象再注册(+=)两个方法--》再执行事件类中触发事件的那个函数--》再解绑其中一个方法--》再次执行事件类中触发事件的函数。
由此可见:事件是拥有可以注册和解绑方法(函数)的功能。