上一篇浅显的总结了一下委托,现在总结一下C#中对事件的理解。
Events
什么是事件
简单而言,事件可以是一个动作或者某一种状态改变,比如单击,按键,鼠标移动,或者系统产生的通知等等。当这些发生的时候,应用程序可以对此做出反应。
在上面的例子中,我们使用了一个click button,当点击按钮时,可以触发点击事件。那么,这个事件的实质是什么呢?我们现在来具体分析一下。
- 首先我们可以从Form1.Designer.cs中发现,定义button被点击事件的语句为:

我们在这条语句上双击“Click”, 按F12 跳转到它的上级方法,会发现跳转到
System.Windows.Forms命名空间的Control方法中对Click定义的事件处理:
以同样的方法选中上面语句中的
EventHandler, 然后按F12 跳转到上级方法。发现:
而当我们点击“click”按钮时,触发的事件处理方法可以在Form1.cs中进行定义,上面的例子为:
1
2
3
4
5private void button1_Click(object sender, EventArgs e)
{
message = textBox1.Text;
sendMessage(message);
}
对比关于委托的介绍,可以发现Click事件的本质可以看作定义了参数为object sender, EventArgs e 的委托。其中,object表示的是发出事件的对象,e代表的是事情的内容,EventArgs是包含事件数据的类的基类,所有事件的参数类都必须派生自System.EventArgs类。如果事件不含参数,可以直接用EventArgs类。例如上面的例子,sender就代表button1,而e代表“click”这个内容。
事实上,C#中的每一个事件,不论是Microsoft本身创建的或是用户自定义的,都基于delegate。
事件的发布者-订阅者模型
事件的发生一般都牵扯到2个角色:
事件发行者(Publisher):一个事件的发行者,也称作是发送者(sender),其实就是一个包含事件和委托定义的对象,这个对象会自行维护本身的状态信息,当本身状态信息变动时,便触发一个事件,并通知所有的事件订阅者。
事件订阅者(Subscriber):对事件感兴趣的对象,也称为Receiver,可以接受事件并为事件提供处理程序,在事件发行者触发一个事件后,会自动执行这段代码。
事件的实现方法
我们可以把自定义事件的实现过程归纳为下面几步:
- 定义
delegate对象类型,两个参数分别为事件的发送者对象,和事件的参数类对象。 - 定义事件的参数类,派生自
System.EventArgs类。如果事件不含参数,则可以省略此过程。 - 定义事件处理方法,与委托具有相同的参数和返回值。
- 用event关键自定义事件对象,也是一个delegate对象。
- 用+=操作符将事件添加到事件队列中。
- 在需要触发事件的地方,编写调用事件触发方法。一般此方法应为
protect访问限制,即不能以public方式调用,但可以被子类继承。名字一般用OnEventName方式命名。 - 调用事件触发方法。
自定义一个事件
现在我们来自己动手定义一个事件。
首先,我们声明一个事件:
假设我们有一张余额为1000的银行卡,现在随机消费,当余额不足时,触发事件,显示超支,然后取消交易。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55namespace ConsoleApplication1
{
class Bank //事件发送者
{
//1. 声明关于事件的委托
public delegate void AlarmEventHandler(object sender,EventArgs e);
//2. 声明事件
public event AlarmEventHandler Alarm;
//3.编写引发事件的函数
public void OnAlarm() {
if (this.Alarm != null) {
Console.WriteLine("System: Insufficient card balance.");
this.Alarm(this ,new EventArgs());
}
}
}
//事件的接收者
class Customer{
//4. 编写事件处理程序
void CustomerHandleAlarm(object sender,EventArgs e) {
Console.WriteLine("Customer: Cancled.");
}
//5. 注册事件处理程序
public Customer(Bank bank) {
bank.Alarm += new Bank.AlarmEventHandler(CustomerHandleAlarm);
}
}
class Program {
static void Main(string[] args) {
Bank bank = new Bank();
Customer customer = new Customer(bank);
double cash = 1000;
while (cash>0) {
Random r = new Random();
double spending = r.Next(100, 200);
double balance = cash - spending;
Console.WriteLine("Costs" + spending);
if (balance < 0) {
Console.WriteLine("overspend... ");
bank.OnAlarm(); //6. 余额不足时触发事件
break;
}
Console.WriteLine("Current balance is: "+balance);
System.Threading.Thread.Sleep(1000);
cash = cash - spending;
}
}
}
}
运行结果如图:
事件处理的委托习惯上以EventHandler结尾,比如上面例子中的AlarmEventHandler, 而事件Alarm实际是事件处理委托AlarmEventHandler的一个实例。引发事件的代码常常写出一个函数,约定为OnEventName,比如上述的OnAlarm()函数。 在Customer类中,我们定义了事件处理程序CustomerHandleAlarm,并把它注册到了bank.Alarm事件中。
自定义事件参数类
刚刚例子里我们自定义了一个事件,其中事件参数应用的是EventArgs类。为了更深刻理解,我们现在再来自定义一个事件参数类。在刚刚例子的基础上自定义一个支付宝花呗事件参数类,如果银行卡余额不足,则使用花呗付款,若超出花呗额度,则取消交易。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69namespace ConsoleApplication1
{
//事件参数
public class HuabeiEventArgs : EventArgs {
public double HuaBei;
//构建函数
public HuabeiEventArgs(double huabei) {
HuaBei = huabei;
}
}
class Bank //事件发送者
{
//1. 声明关于事件的委托
public delegate void AlarmEventHandler(object sender,HuabeiEventArgs e);
//2. 声明事件
public event AlarmEventHandler Alarm;
//3.编写引发事件的函数,引入了事件函数HuabeiEventArgs e
public void OnAlarm(HuabeiEventArgs e) {
if (this.Alarm != null) {
Console.WriteLine("System: Insufficient card balance.");
this.Alarm(this,e);
}
}
}
//事件的接收者
class Customer{
//4. 编写事件处理程序,参数包含HuaBei 信息
void CustomerHandleAlarm(object sender,HuabeiEventArgs e) {
if (e.HuaBei>2500) {
Console.WriteLine("Customer: Cancled.");
}
else {
Console.WriteLine("支付宝花呗消费了{0}",e.HuaBei);
}
}
//5. 注册事件处理程序
public Customer(Bank bank) {
bank.Alarm += new Bank.AlarmEventHandler(CustomerHandleAlarm);
}
}
class Program {
static void Main(string[] args) {
Bank bank = new Bank();
Customer customer = new Customer(bank);
double cash = 1000;
while (cash>0) {
Random r = new Random();
double spending = r.Next(100, 200);
double balance = cash - spending;
Console.WriteLine("Costs" + spending);
if (balance < 0) {
Console.WriteLine("overspend... ");
HuabeiEventArgs e = new HuabeiEventArgs(spending);
bank.OnAlarm(e); //6. 余额不足时触发事件
break;
}
Console.WriteLine("Current balance is: "+balance);
System.Threading.Thread.Sleep(1000);
cash = cash - spending;
}
}
}
}
运行结果如图:
以上。
[1]:参考 https://www.codeproject.com/Articles/1009930/
[2]:参考 https://www.codeproject.com/Articles/4773/Events-and-Delegates-simplified
[3]:参考 http://blog.csdn.net/jamestaosh/article/details/4372172