C#学习笔记——事件机制
事件机制简介:
任何进行过图形用户界面开发的编程人员都会知道事件的概念。当用户在使用程序的时候,用户必然要和程序进行一定的交互。比如当用户点击窗体上的一个按钮后,程序就会产生该按钮被点击的事件,并通过相应的事件处理函数来响应用户的操作。这样用户的直观感觉就是程序执行了我要求的任务了。当然,事件并不一定是在和用户交互的情况下才会产生的,系统的内部也会产生一些事件并请求处理的,比如时钟事件就是一个很好例子。不过要介绍C#中的事件处理机制(扩展到更广的范围便是整个.Net框架),我们首先得明白一个叫"委托"的概念。
C#中的委托:
委托,顾名思义,就是中间代理人的意思。C#中的委托允许你将一个对象中的方法传递给另一个能调用该方法的类的某个对象。你可以将类A中的一个方法m(被包含在某个委托中了)传递给一个类B,这样类B就能调用类A中的方法m了。同时,你还可以以静态(static)的方式或是实例(instance)的方式来传递该方法。所以这个概念和C++中的以函数指针为参数形式调用其他类中的方法的概念是十分类似的。
C#中的事件处理函数:
C#中的事件处理函数是一个具有特定参数形式的委托对象,其形式如下:
public delegate void EventNameEventHandler(object sender, EventNameEventArgs e);
(其中第一个参数(sender)指明了触发该事件的对象,第二个参数(e)包含了在事件处理函数中可以被运用的一些数据。上面的MyEventArgs类是从EventArgs类继承过来的,后者是一些更广泛运用的类,如MouseEventArgs类、ListChangedEventArgs类等的基类。对于基于GUI的事件,你可以运用这些更广泛的、已经被定义好了的类的对象来完成处理;而对于那些基于非GUI的事件,你必须要从EventArgs类派生出自己的类,并将所要包含的数据传递给委托对象。)
编写一个“事件”的四个步骤:
1)在事件发行者中定义一个事件;
2)在事件发行者中触发事件;
3)在事件订阅者中定义事件处理程序; 4)向事件发行者订阅一个事件。
演示示例:
程序界面:
源码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace CSharp_004_事件机制
{
public partial class frmMain : Form
{
Publisher SanDongPublisher = new Publisher();
Subscriber ZhangSan = new Subscriber("张三");
Subscriber LiSi = new Subscriber("李四");
public frmMain()
{
InitializeComponent();
}
private void btnIssueComputer_Click(object sender, EventArgs e)
{
SanDongPublisher.issueComputer();
}
private void btnIssueLife_Click(object sender, EventArgs e)
{
SanDongPublisher.issueLife();
}
private void chkComputerZs_CheckedChanged(object sender, EventArgs e)
{
if (true==chkComputerZs.Checked)
{
SanDongPublisher.OnPubComputer += new Publisher.Courier(ZhangSan.ReceiveMagazine);
}
else
{
SanDongPublisher.OnPubComputer -= new Publisher.Courier(ZhangSan.ReceiveMagazine);
}
}
private void chkLifeZs_CheckedChanged(object sender, EventArgs e)
{
if (true == chkLifeZs.Checked)
{
SanDongPublisher.OnPubLife += new Publisher.Courier(ZhangSan.ReceiveMagazine);
}
else
{
SanDongPublisher.OnPubLife -= new Publisher.Courier(ZhangSan.ReceiveMagazine);
}
}
private void chkComputerLs_CheckedChanged(object sender, EventArgs e)
{
if (true == chkComputerLs.Checked)
{
SanDongPublisher.OnPubComputer += new Publisher.Courier(LiSi.ReceiveMagazine);
}
else
{
SanDongPublisher.OnPubComputer -= new Publisher.Courier(LiSi.ReceiveMagazine);
}
}
private void chkLifeLs_CheckedChanged(object sender, EventArgs e)
{
if (true == chkLifeLs.Checked)
{
SanDongPublisher.OnPubLife += new Publisher.Courier(LiSi.ReceiveMagazine);
}
else
{
SanDongPublisher.OnPubLife -= new Publisher.Courier(LiSi.ReceiveMagazine);
}
}
}
public class Publisher //出版社
{
public delegate void Courier(string magazineName); //申明事件所需的委托(邮递员)
public event Courier OnPubComputer; //声明事件
public event Courier OnPubLife;
public void issueComputer() //触发事件的方法
{
if (OnPubComputer != null)
{
//MessageBox.Show("发行《电脑》杂志");
OnPubComputer("《电脑》杂志");
}
}
public void issueLife()
{
if (OnPubLife != null)
{
//MessageBox.Show("发行《生活》杂志");
OnPubLife("《生活》杂志");
}
}
}
public class Subscriber //用户
{
private string userName;
public Subscriber(string name)
{
this.userName = name;
}
public void ReceiveMagazine(string magazineName)
{
MessageBox.Show(userName+"已经收到"+magazineName);
}
}
}
其中,
出版社类:
1: public class Publisher //出版社
2: {
3: public delegate void Courier(string magazineName); //申明事件所需的委托(邮递员)
4:
5: public event Courier OnPubComputer; //声明事件
6: public event Courier OnPubLife;
7:
8: public void issueComputer() //触发事件的方法
9: {
10: if (OnPubComputer != null)
11: {
12: //MessageBox.Show("发行《电脑》杂志");
13: OnPubComputer("《电脑》杂志");
14: }
15: }
16: public void issueLife()
17: {
18: if (OnPubLife != null)
19: {
20: //MessageBox.Show("发行《生活》杂志");
21: OnPubLife("《生活》杂志");
22: }
23: }
24: }
用户(订阅者 )类:
1: public class Subscriber //用户
2: {
3: private string userName;
4: public Subscriber(string name)
5: {
6: this.userName = name;
7: }
8:
9: public void ReceiveMagazine(string magazineName)
10: {
11: MessageBox.Show(userName+"已经收到"+magazineName);
12: }
13: }
.NET Framework事件设计准则:
4)在引发事件的类中提供一个受保护的方法。以OnEventName命名。在该方法中引发该事件。
具体步骤:
1)确定事件的名称:EventName。
2)确定委托的名称:EventNameEventHandler。
3)定义提供事件数据的类,以EventNameEventArgs命名。
4)在引发事件的类中提供一个受保护的方法。以OnEventName命名。
代码形式:
public delegate void EventNameEventHandler(object sender, EventNameEventArgs e);
/*如果事件不传递任何数据,也要声明sender和e两个参数,e参数可以直接使用
System.EventArgs类声明;*/
/*如果事件需要传递数据,e参数需使用System.EventArgs派生出的EventNameEventArgs类声明
。*/
public event EventNameEventHandler EventName;
//在引发事件的类中提供一个受保护的方法。以OnEventName命名。在该方法中引发该事件。 protected virtual void OnEventName(EventNameEventArgs e) { EventNameEventHandler handler = EventName; if(handler != null) { handler(this,e); } }
下面我们把演示示例中的代码规范化:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace CSharp_004_事件机制
{
public partial class frmMain : Form
{
Publisher SanDongPublisher = new Publisher();
Subscriber ZhangSan = new Subscriber("张三");
Subscriber LiSi = new Subscriber("李四");
public frmMain()
{
InitializeComponent();
}
private void btnIssueComputer_Click(object sender, EventArgs e)
{
SanDongPublisher.issueComputer("《电脑》杂志", DateTime.Now.ToLocalTime());
}
private void chkComputerZs_CheckedChanged(object sender, EventArgs e)
{
if (true == chkComputerZs.Checked)
{
SanDongPublisher.PubComputer += new Publisher.PubComputerEventHandler(ZhangSan.ReceiveMagazine);
}
else
{
SanDongPublisher.PubComputer -= new Publisher.PubComputerEventHandler(ZhangSan.ReceiveMagazine);
}
}
private void chkComputerLs_CheckedChanged(object sender, EventArgs e)
{
if (true == chkComputerLs.Checked)
{
SanDongPublisher.PubComputer += new Publisher.PubComputerEventHandler(LiSi.ReceiveMagazine);
}
else
{
SanDongPublisher.PubComputer -= new Publisher.PubComputerEventHandler(LiSi.ReceiveMagazine);
}
}
private void btnIssueLife_Click(object sender, EventArgs e)
{
SanDongPublisher.issueLife("《生活》杂志", DateTime.Now.ToLocalTime());
}
private void chkLifeZs_CheckedChanged(object sender, EventArgs e)
{
if (true == chkLifeZs.Checked)
{
SanDongPublisher.PubLife += new Publisher.PubLifeEventHandler(ZhangSan.ReceiveMagazine);
}
else
{
SanDongPublisher.PubLife -= new Publisher.PubLifeEventHandler(ZhangSan.ReceiveMagazine);
}
}
private void chkLifeLs_CheckedChanged(object sender, EventArgs e)
{
if (true == chkLifeLs.Checked)
{
SanDongPublisher.PubLife += new Publisher.PubLifeEventHandler(LiSi.ReceiveMagazine);
}
else
{
SanDongPublisher.PubLife -= new Publisher.PubLifeEventHandler(LiSi.ReceiveMagazine);
}
}
}
public class PubEventArgs : EventArgs
{
private readonly string m_magazineName;
private readonly DateTime m_dateTime;
public PubEventArgs(string magazimeName,DateTime dateTime)
{
m_magazineName = magazimeName;
m_dateTime = dateTime;
}
public string magezineName
{
get { return m_magazineName;}
}
public DateTime dateTime
{
get { return m_dateTime;}
}
}
public class Publisher //出版社
{
public delegate void PubComputerEventHandler(Object sender,PubEventArgs e); //申明事件所需的委托(邮递员)
public delegate void PubLifeEventHandler(Object sender, PubEventArgs e);
public event PubComputerEventHandler PubComputer; //声明事件
public event PubLifeEventHandler PubLife;
protected virtual void OnPubComputer(PubEventArgs e)
{
PubComputerEventHandler handler = PubComputer;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnPubLife(PubEventArgs e)
{
PubLifeEventHandler handler = PubLife;
if (handler != null)
{
handler(this, e);
}
}
public void issueComputer(string magazimeName,DateTime issueDateTime) //触发事件的方法
{
OnPubComputer(new PubEventArgs(magazimeName,issueDateTime));
}
public void issueLife(string magazimeName, DateTime issueDateTime) //触发事件的方法
{
OnPubLife(new PubEventArgs(magazimeName, issueDateTime));
}
}
public class Subscriber //用户
{
private string userName;
public Subscriber(string name)
{
this.userName = name;
}
public void ReceiveMagazine(Object sender, PubEventArgs e)
{
MessageBox.Show(e.dateTime + " " +userName + "已经收到" + e.magezineName);
}
}
}
出版社类:
1: public class Publisher //出版社
2: {
3: public delegate void PubComputerEventHandler(Object sender,PubEventArgs e); //申明事件所需的委托(邮递员)
4: public delegate void PubLifeEventHandler(Object sender, PubEventArgs e);
5:
6: public event PubComputerEventHandler PubComputer; //声明事件
7: public event PubLifeEventHandler PubLife;
8:
9: protected virtual void OnPubComputer(PubEventArgs e)
10: {
11: PubComputerEventHandler handler = PubComputer;
12: if (handler != null)
13: {
14: handler(this, e);
15: }
16: }
17:
18: protected virtual void OnPubLife(PubEventArgs e)
19: {
20: PubLifeEventHandler handler = PubLife;
21: if (handler != null)
22: {
23: handler(this, e);
24: }
25: }
26:
27: public void issueComputer(string magazimeName,DateTime issueDateTime) //触发事件的方法
28: {
29: OnPubComputer(new PubEventArgs(magazimeName,issueDateTime));
30: }
31: public void issueLife(string magazimeName, DateTime issueDateTime) //触发事件的方法
32: {
33: OnPubLife(new PubEventArgs(magazimeName, issueDateTime));
34: }
35: }
用户(订阅者 )类:
1: public class Subscriber //用户
2: {
3: private string userName;
4: public Subscriber(string name)
5: {
6: this.userName = name;
7: }
8:
9: public void ReceiveMagazine(Object sender, PubEventArgs e)
10: {
11: MessageBox.Show(e.dateTime + " " +userName + "已经收到" + e.magezineName);
12: }
13: }
为事件提供数据的类:
1: public class PubEventArgs : EventArgs
2: {
3: private readonly string m_magazineName;
4: private readonly DateTime m_dateTime;
5: public PubEventArgs(string magazimeName,DateTime dateTime)
6: {
7: m_magazineName = magazimeName;
8: m_dateTime = dateTime;
9: }
10: public string magezineName
11: {
12: get { return m_magazineName;}
13: }
14: public DateTime dateTime
15: {
16: get { return m_dateTime;}
17: }
18: }