C#第十三讲事件老师讲义.docx
《C#第十三讲事件老师讲义.docx》由会员分享,可在线阅读,更多相关《C#第十三讲事件老师讲义.docx(21页珍藏版)》请在冰豆网上搜索。
C#第十三讲事件老师讲义
第十三讲委托和事件
上章回顾:
了解什么是索引指示器
如何实现索引指示器
索引器和数组的比较
索引器和属性的不同点
重载索引指示器
了解如何实现多参数的索引指示器
本章目标:
了解什么是委托
掌握委托如何代理静态和动态的方法
掌握委托链的好处
了解匿名方法
了解什么是事件
理解事件发行者和事件订阅者
掌握事件的四个步骤
.NetFramework的事件设计准则
一、委托
委托声明定义了一种类型,它用一组特定的参数以及返回类型来封装方法。
对于静态方法,委托对象封装要调用的方法。
对于实例方法,委托对象同时封装一个实例和该实例上的一个方法。
如果您有一个委托对象和一组适当的参数,则可以用这些参数调用该委托
(一)委托代理静态的方法
委托包含的方法,必须与委托具备同样的返回类型和同样的参数类型
(1)
usingSystem;
namespaceDelegateApp
{
classMyDelegate
{
staticvoidzsEat(stringfood)
{
Console.WriteLine("张三吃"+food);
}
staticvoidMain(string[]args)
{
zsEat("西瓜");
}
}
}
(2)
usingSystem;
namespaceDelegateApp
{
delegatevoidEatDelegate(stringname);
classMyDelegate
{
staticvoidzsEat(stringfood)
{
Console.WriteLine("张三吃"+food);
}
staticvoidMain(string[]args)
{
EatDelegatezs=newEatDelegate(zsEat);
zs("西瓜");
}
}
}
(3)
usingSystem;
namespaceDelegateApp
{
delegatevoidEatDelegate(stringname);
classMyDelegate
{
staticvoidzsEat(stringfood)
{
Console.WriteLine("张三吃"+food);
}
staticvoidlsEat(stringfood)
{
Console.WriteLine("李四吃"+food);
}
staticvoidwwEat(stringfood)
{
Console.WriteLine("王五吃"+food);
}
staticvoidMain(string[]args)
{
EatDelegatezs=newEatDelegate(zsEat);
EatDelegatels=newEatDelegate(lsEat);
EatDelegateww=newEatDelegate(wwEat);
zs("西瓜");
ls("西瓜");
ww("西瓜");
}
}
}
二、委托链:
像调用方法一样调用这个委托链它就会依次按照加入的顺序去执行这几个委托所对应的函数。
(4)
usingSystem;
namespaceDelegateApp
{
delegatevoidEatDelegate(stringname);
classMyDelegate
{
staticvoidzsEat(stringfood)
{
Console.WriteLine("张三吃"+food);
}
staticvoidlsEat(stringfood)
{
Console.WriteLine("李四吃"+food);
}
staticvoidwwEat(stringfood)
{
Console.WriteLine("王五吃"+food);
}
staticvoidMain(string[]args)
{
EatDelegatezs=newEatDelegate(zsEat);
EatDelegatels=newEatDelegate(lsEat);
EatDelegateww=newEatDelegate(wwEat);
EatDelegateeatChain;
eatChain=zs+ls+ww;
eatChain("西瓜");
}
}
}
(5)
usingSystem;
namespaceDelegateApp
{
delegatevoidEatDelegate(stringname);
classMyDelegate
{
staticvoidzsEat(stringfood)
{
Console.WriteLine("张三吃"+food);
}
staticvoidlsEat(stringfood)
{
Console.WriteLine("李四吃"+food);
}
staticvoidwwEat(stringfood)
{
Console.WriteLine("王五吃"+food);
}
staticvoidMain(string[]args)
{
EatDelegatezs=newEatDelegate(zsEat);
EatDelegatels=newEatDelegate(lsEat);
EatDelegateww=newEatDelegate(wwEat);
EatDelegateeatChain;
Console.WriteLine("张三、李四、王五开座谈会");
eatChain=zs+ls+ww;
eatChain("西瓜");
Console.WriteLine("李四出去接电话");
eatChain-=ls;
eatChain("香蕉");
Console.WriteLine("李四回来了");
eatChain+=ls;
eatChain("桔子");
}
}
}
三、匿名方法
匿名方法由关键字delegate、可选的参数列表和包含在{和}分隔符中的语句列表组成。
匿名方法允许将一段委托关联的代码以代码块的方式内嵌到使用委托的地方,可以省略委托方法的构造过程。
EatDelegateeatChain=null;
eatChain+=delegate(stringfood){Console.WriteLine("张三吃"+food);};
eatChain+=delegate(stringfood){Console.WriteLine("李四吃"+food);};
eatChain+=delegate(stringfood){Console.WriteLine("王五吃"+food);};
eatChain("西瓜");
(二)委托代理动态的方法
(6)
usingSystem;
namespaceDelegateApp
{
delegatevoidEatDelegate(stringname);
classMan
{
privatestringname;
publicMan(stringname)
{
this.name=name;
}
publicvoidEat(stringfood)
{
Console.WriteLine(name+"吃"+food);
}
}
classParty
{
staticvoidMain(string[]args)
{
ManZS=newMan("张三");
ManLS=newMan("李四");
ManWW=newMan("王五");
EatDelegatezs=newEatDelegate(ZS.Eat);
EatDelegatels=newEatDelegate(LS.Eat);
EatDelegateww=newEatDelegate(WW.Eat);
EatDelegateeatChain=null;
Console.WriteLine("张三、李四、王五开座谈会");
eatChain=zs+ls+ww;
eatChain("西瓜");
Console.WriteLine("李四出去接电话");
eatChain-=ls;
eatChain("香蕉");
Console.WriteLine("李四回来了");
eatChain+=ls;
eatChain("桔子");
}
}
}
(7)
usingSystem;
namespaceDelegateApp
{
delegatevoidEatDelegate(stringname);
classMan
{
privatestringname;
publicMan(stringname)
{
this.name=name;
}
publicvoidEat(stringfood)
{
Console.WriteLine(name+"吃"+food);
}
}
classParty
{
staticvoidEatTogether(stringfood,paramsEatDelegate[]values)
{
if(values==null)
{
Console.WriteLine("座谈会结束了");
}
else
{
EatDelegateeatChian=null;
foreach(EatDelegateedinvalues)
{
eatChian+=ed;
}
eatChian(food);
Console.WriteLine();
}
}
staticvoidMain(string[]args)
{
ManZS=newMan("张三");
ManLS=newMan("李四");
ManWW=newMan("王五");
EatDelegatezs=newEatDelegate(ZS.Eat);
EatDelegatels=newEatDelegate(LS.Eat);
EatDelegateww=newEatDelegate(WW.Eat);
Console.WriteLine("张三、李四、王五开座谈会");
EatTogether("西瓜",zs,ls,ww);
Console.WriteLine("李四出去接电话");
EatTogether("香蕉",zs,ww);
Console.WriteLine("李四回来了");
EatTogether("桔子",zs,ls,ww);
EatTogether(null,null);
}
}
}
四、事件
事件是对象发送的消息,以发信号通知操作的发生。
例如,封装用户界面控件的类可以定义一个在用户单击该控件时发生的事件。
控件类不关心单击按钮时发生了什么,但它需要告知派生类单击事件已发生。
然后,派生类可选择如何响应。
(一)事件发行者(Publisher)
一个事件发行者,也称作发送者(sender),其实就是一个对象,这个对象会自行维护本身的状态信息。
当本身状态信息变动时,便触发一个事件,并通知所有的事件订阅者。
(二)事件订阅者(Subscriber):
对事件感兴趣的对象,也称为接受者(Receiver),可以注册感兴趣的事件,通常需提供一个事件处理程序,在事件发行者触发一个事件后,会自动执行这段代码的内容。
(8)
usingSystem;
namespaceEventApp
{
classPublisher//出版社
{
publicdelegatevoidPublish();//声明事件所需的代理
publiceventPublishOnPublish;//事件的声明
publicvoidIssue()//触发事件的方法
{
if(OnPublish!
=null)
{
Console.WriteLine("发行刊物");
OnPublish();
}
}
}
classSubScriber//订阅者
{
publicvoidReceive()//在事件订阅者中定义事件处理程序
{
Console.WriteLine("订阅者已经收到了刊物");
}
}
classStory
{
staticvoidMain()
{
PublisherPub=newPublisher();
SubScriberzs=newSubScriber();
Pub.OnPublish+=newPublisher.Publish(zs.Receive);//向事件发行者订阅一个事件
Pub.Issue();//触发事件
}
}
}
(9)
usingSystem;
namespaceEventApp
{
classPublisher//出版社
{
publicdelegatevoidPubComeputer(stringmagazineName);//声明事件所需的代理
publicdelegatevoidPubLife(stringmagazineName);
publiceventPubComeputerOnPubComputer;//事件的声明
publiceventPubLifeOnPubLife;
publicvoidIssueComputer()//触发事件的方法
{
if(OnPubComputer!
=null)
{
Console.WriteLine("发行<<电脑>>刊物");
OnPubComputer("电脑杂志");
}
}
publicvoidIssueLife()//触发事件的方法
{
if(OnPubLife!
=null)
{
Console.WriteLine("发行<<生活>>刊物");
OnPubLife("生活杂志");
}
}
}
classSubScriber//订阅者
{
privatestringname;
publicSubScriber(stringname)
{
this.name=name;
}
publicvoidReceive(stringmagazineName)//在事件订阅者中定义事件处理程序
{
Console.WriteLine(name+"已经收到"+magazineName);
}
}
classStory
{
staticvoidMain()
{
PublisherPub=newPublisher();
SubScriberzs=newSubScriber("张三");
Pub.OnPubComputer+=newPublisher.PubComeputer(zs.Receive);//向事件发行者订阅一个事件
SubScriberls=newSubScriber("李四");
Pub.OnPubComputer+=newPublisher.PubComeputer(ls.Receive);
Pub.OnPubLife+=newPublisher.PubLife(ls.Receive);
Pub.IssueComputer();//触发事件
Pub.IssueLife();
Console.WriteLine();
Console.WriteLine("一年以后");
Pub.OnPubComputer-=newPublisher.PubComeputer(ls.Receive);
Pub.IssueComputer();//触发事件
Pub.IssueLife();
}
}
}
五、事件的四个步骤
在事件发行者中定义一个事件
在事件发行者中触发事件
在事件订阅者中定义事件处理程序
向事件发行者订阅一个事件
六、.NetFramework的事件设计准则
(1)事件的命名准则使用pascalcasing命名方式
(2)声明delegate时,使用void类型当作返回值,eventName事件的事件委托是eventNameEventHandler,事件接受两个传入参数,一律命为sender与e
publicdelegatevoidEventNameEventHandler(objectsender,EventNameArgse);
(3)定义一个提供事件数据的类。
对类以EventNameEventArgs进行命名,从System.eventArgs派生该类,然后添加所有事件特定的成员
(4)如果事件不需要传递任何数据,也要声明两个参数
e参数可以直接使用系统提供的System.EventArgs类。
如果需要传递数据,则要从System。
EventArgs继承一个类,并把数据放在里面。
PublicdelegatevoidEventNameEventHandler(objectsender,EventArgse);
PubliceventEventNameEventHandlerEventName;
(5)在引发事件的类中提供了一个受保护的方法。
以OnEventName进行命名。
在该方法中引发该事件
protectedvirtualvoidOnEventName(EventArgse)
{
if(EventName!
=null)
{
EventName(this,e);
}}
(10)
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
namespaceEventApp
{
classPubEventArgs:
EventArgs
{
publicPubEventArgs(stringm_magazineName,DateTimem_pubDate)
{
this.magazineName=m_magazineName;
this.pubDate=m_pubDate;
}
privatereadonlystringmagazineName;
publicstringMagazineName
{
get{returnmagazineName;}
}
privatereadonlyDateTimepubDate;
publicDateTimePubDate
{
get{returnpubDate;}
}
}
classPubliser
{
publicdelegatevoidPubComputerEventHandler(objectsender,PubEventArgse);
publicdelegatevoidPubLifeEventHandler(objectsender,PubEventArgse);
publiceventPubComputerEventHandlerPubComputer;
publiceventPubLifeEventHandlerPubLife;
protectedvirtualvoidOnPubComputer(PubEventArgse)
{
if(PubComputer!
=null)
{
PubComputer(this,e);
}
}
protectedvirtualvoidOnPubLife(PubEventArgse)
{
if(PubLife!
=null)
{
PubLife(this,e);
}
}
publicvoidIssueComputer(stringmagazineName,DateTimepubDate)
{
Console.WriteLine("发行"+magazineName);
OnPubComputer(newPubEventArgs(magazineName,pubDate));
}
publicvoidIssueLife(stringmagazineName,DateTimepubDate)
{
Console.WriteLine("发行"+magazineName);
OnPubLife(newPubEventArgs(magazineName,pubDate));
}
}
classSubScriber
{
privatestringname;
publicSubScriber(stringname)
{
this.name=name;
}
publicvoidRecevice(objectsender,PubEventArgse)
{
Console.WriteLine(e.PubDate+""+name+"已经收到"+e.MagazineName);
}
}
classStory
{
staticvoidMain(string[]args)
{
Publiserpub=newPubliser();
SubScriberzs=newSubScriber("张三");
pub.PubComputer+=newPubliser.PubComputerEventHandler(zs.Recevice);
SubScriberls=newSubScriber("李四");
pub.PubComputer+=newPubliser.PubComputerEventHandler(ls.Rec