C#事件(Event)的理解
事件的定义:
C# 事件(Event): 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。
事件是委托的一个实例。
事件需要在类中声明。
事件使用 发布-订阅(publisher-subscriber) 模型。
发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。
订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。
事件的类型
事件一般分为两种:
-
带参数传递的
-
不带参数传递的
基于上述的理解,实现 .Net 框架中的事件需要三个步骤。
-
实现事件的发布类
-
实现事件的订阅类
-
实现发布和订阅的关联(类似Qt中的信号关联)。
注意:
发布类里应当实现:
1、事件的触发(类似Qt中的发送信号emit signal));
2、事件的引发方法
订阅类中应当实现:
事件接收时的操作,(Qt 中信号槽Slot)
现在来看下面的两个例子,如下:
1、不带参数传递的事件
namespace SimpleEvent
{
/***********发布器类***********/
public class EventTest
{
private int value; //定义一个参数
public delegate void NumManipulationHandler();
public event NumManipulationHandler ChangeNum;
protected virtual void OnNumChanged()
{
if (ChangeNum != null)
{
ChangeNum(); /* 事件被触发 */
}
else
{
Console.WriteLine("event not triggered");
Console.ReadKey(); /* 回车继续 */
}
}
public EventTest() //构造函数
{
int n = 5;
SetValue(n); //将值设置为5
}
public void SetValue(int n)
{
// value = Console.ReadKey();
if (value != n)
{
value = n;
OnNumChanged(); //当前后的值放生变化的时候触发事件
}
}
}
/***********订阅器类***********/
public class subscribEvent
{
public void printf()
{
Console.WriteLine("event has been triggered");
Console.ReadKey(); /* 回车继续 */
}
}
/***********触发***********/
public class MainClass
{
public static void Main()
{
EventTest e = new EventTest(); /* 实例化发布者对象,第一次没有触发事件,屏幕上显示“event not triggered" */
subscribEvent v = new subscribEvent(); /* 实例化订阅者对象 */
e.ChangeNum += new EventTest.NumManipulationHandler(v.printf); /* 注册 */
e.SetValue(7); //第二次触发事件,屏幕上显示event has been triggered
e.SetValue(11); //第三次触发事件,屏幕上显示event has been triggered
}
}
}
2、带参数传递的
namespace EventDemo
{
/// <summary>
/// 发布事件的类
/// </summary>
public class TestEventSource
{
//定义事件参数类
public class TestEventArgs : EventArgs
{
public readonly char KeyToRaiseEvent; //键盘值;
public TestEventArgs(char keyToRaiseEvent)
{
KeyToRaiseEvent = keyToRaiseEvent;
}
}
//定义delegate
public delegate void TestEventHandler(object sender, TestEventArgs e); //sender:事件发布者;e:传递事件的参数
//用event 关键字声明事件对象
public event TestEventHandler TestEvent;
//事件触发方法
protected virtual void OnTestEvent(TestEventArgs e)
{
if (TestEvent != null)
TestEvent(this, e); // 触发事件;发布者不为空,即触发事件
}
//引发事件
public void RaiseEvent(char keyToRaiseEvent)
{
TestEventArgs e = new TestEventArgs(keyToRaiseEvent);
OnTestEvent(e);
}
}
}
namespace EventDemo
{
/// <summary>
/// 监听事件的类
/// </summary>
public class TestEventListener
{
//定义处理事件的方法,他与声明事件的delegate具有相同的参数和返回值类型
public void KeyPressed(object sender, TestEventSource.TestEventArgs e)
{
Console.WriteLine("发送者:{0},所按得健为:{1}", sender, e.KeyToRaiseEvent);
}
//订阅事件
public void Subscribe(TestEventSource evenSource)
{
evenSource.TestEvent += new TestEventSource.TestEventHandler(KeyPressed); //将发布者的testEvent 方法与订阅者的KeyPressed方法关联
}
//取消订阅事件
public void UnSubscribe(TestEventSource evenSource)
{
evenSource.TestEvent -= new TestEventSource.TestEventHandler(KeyPressed);
}
}
}
namespace EventDemo
{
class Program
{
static void Main(string[] args)
{
//创建事件源对象
TestEventSource es = new TestEventSource();
//创建监听对象
TestEventListener el = new TestEventListener();
//订阅事件
Console.WriteLine("订阅事件\n");
el.Subscribe(es);
//引发事件
Console.WriteLine("输入一个字符,再按enter键");
string s = Console.ReadLine();
es.RaiseEvent(s.ToCharArray()[0]);
//取消订阅事件
Console.WriteLine("\n取消订阅事件\n");
el.UnSubscribe(es);
//引发事件
Console.WriteLine("输入一个字符,再按enter健");
s = Console.ReadLine();
es.RaiseEvent(s.ToCharArray()[0]);
}
}
}
在上述例子中:
TestEventSource类。他就相当于windows控件类一样,是事件的源,里面包含有事件的声明,以及存储调用参数的事件参数类,以及事件的触发方法。
TestEventListener类。他提供了事件处理程序,并实现了事件处理程序和事件对象的邦定。
Test 类,实例化自定义事件的事件源对象,并调用 TestEventListener类中的Subscribe(es);方法进行事件对象和事件处理程序的邦定(订阅事件),调用 TestEventSource类中的RaiseEvent(char keyToRaiseEvent)引发对象,并有对象所指定的委托回调处理事件。完成整个自定义事件。
其中 RaiseEvent(char keyToRaiseEvent) 就相当于main()一样是自定义事件的执行入口, 从这个法开始—〉调用事件委托----〉查找订阅事件程序找到事件所封装的方法集----〉由委托回调事件处理程序并传递参数—〉执行事件处理程序。