一 概要
本文通过实例介绍了.NET事件的使用方法。
二 实例演示
1 新建Windows应用程序EventExp,程序结构如下图所示。
图1 程序结构图
2 新建教师类Teacher(类文件为Teacher.cs),Teacher类为事件发布者。
Teacher类的详细代码如下所示。
//************************************************************
//
// CLR事件示例代码
//
// Author:三五月儿
//
// Date:2014/08/31
//
// http://blog.csdn.net/yl2isoft
//
//************************************************************
using System;
using System.Windows.Forms;
namespace EventExp
{
public class Teacher
{
public Teacher (){}
public event EventHandler<AskEventArgs> Ask;
public void Raise()
{
MessageBox.Show("MrWang:Who is on duty today?");
RaiseDutyInfo();
}
private void RaiseDutyInfo()
{
EventHandler<AskEventArgs> ask = Ask;
if (ask != null)
{
ask(this, new AskEventArgs());
}
}
}
public class AskEventArgs : EventArgs
{
}
}
Teacher类中定义类型为EventHandler<AskEventArgs>的事件Ask,该事件在方法RaiseDutyInfo中触发,在事件被触发前会向窗体弹出"MrWang:Who is on duty today?”的消息框。
查看EventHandler<AskEventArgs>类型的定义,如下所示:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
从定义中可以了解到,EventHandler<AskEventArgs>本质上是一个委托,该委托使用带两个参数且不具有返回值的方法,第一个参数是包含事件发布者的对象,而第二个参数提供与事件相关的信息,该参数必须派生自EventArgs类,本实例中不需要提供任何与事件相关的信息,所以AskEventArgs类不包含任何实现代码。本例中使用的EventHandler<AskEventArgs>由.NET定义,当然我们也可以自己定义所需的事件类型,关于这点等以后有机会再探讨。
3 新建学生类Student(类文件为Student.cs),Student类为事件的订阅者。
Student类的详细代码如下所示。
//************************************************************
//
// CLR事件示例代码
//
// Author:三五月儿
//
// Date:2014/08/31
//
// http://blog.csdn.net/yl2isoft
//
//************************************************************
using System.Windows.Forms;
namespace EventExp
{
public class Student
{
private string name;
private bool isOnDuty;
public Student(string name, bool isOnDuty)
{
this.name = name;
this.isOnDuty = isOnDuty;
}
public void Answer(object sender, AskEventArgs e)
{
if (isOnDuty)
{
MessageBox.Show(string.Format("{0}:{0} is on duty today!", name, name));
}
else
{
MessageBox.Show(string.Format("{0}:{0} is not on duty today!", name, name));
}
}
}
}
Student类的Answer方法满足EventHandler<AskEventArgs>委托的要求,所以该方法可以作为Teacher类的Ask事件的事件处理方法。
4 程序的主画面如下图所示。
图2 程序主画面
程序主画面的后端代码如下所示。
//************************************************************
//
// CLR事件示例代码
//
// Author:三五月儿
//
// Date:2014/08/31
//
// http://blog.csdn.net/yl2isoft
//
//************************************************************
using System;
using System.Windows.Forms;
namespace EventExp
{
public partial class Form1 : Form
{
Student zhangSan;
Student liSi;
Student wangWu;
Student tiana;
Teacher mrWang;
public Form1()
{
InitializeComponent();
zhangSan = new Student("张三", true);
liSi = new Student("李四", true);
wangWu = new Student("王五", true);
tiana = new Student("三五月儿", false);
mrWang = new Teacher();
//订阅事件
mrWang.Ask += zhangSan.Answer;
mrWang.Ask += liSi.Answer;
mrWang.Ask += wangWu.Answer;
mrWang.Ask += tiana.Answer;
//取消订阅事件
mrWang.Ask -= liSi.Answer;
mrWang.Ask -= wangWu.Answer;
}
private void button1_Click(object sender, EventArgs e)
{
mrWang.Raise();
}
}
}
在Form1类中,实例化Student类,得到学生对象zhangSan、liSi、wangWu及tiana,先让所有学生对象都订阅Teacher对象mrWang的Ask事件,随后取消liSi与wangWu两位同学的事件订阅。这样一来,mrWang的Ask事件被触发后,zhangSan和tiana将会执行自己的事件处理方法,而liSi与wangWu将不会,因为他们无法感知到mrWang的Ask事件的发生。zhangSan和tiana在自己的事件处理方法中,会弹出消息框,显示“zhangSan:zhangSan is on duty today!”和“三五月儿:三五月儿 is not on duty today!”。
5 程序运行后的效果如下图所示,与第4步的分析结果保持一致。
图3 程序运行效果图
三 总结
1 事件是基于委托的。
2 事件编程模型包含事件发布者,事件订阅者以及两者之间的订阅关系三部分。
3 事件编程模型是观察者模式的一种实现。
4 使用事件编程模型一般包含以下几步:
- 定义事件的类型参数(AskEventArgs类)
- 定义事件发布者的类(Teacher类)
- 在事件发布者的类中定义事件(Teacher类的Ask事件)
- 在事件发布者的类中定义事件通知方法,事件将在该方法中被触发,方法被触发后会去执行事件处理方法(Teacher类的RaiseDutyInfo方法)
- 定义事件订阅者的类(Student类)
- 在事件订阅者的类中定义事件处理方法,该方法的定义必须满足事件使用的委托的定义一致(Student类的Answer方法)
- 订阅事件(Form1中通过“+=”和“-=”完成事件的订阅及取消订阅的操作)