某市政府信息網(wǎng)站建設(shè)方案廈門人才網(wǎng)最新招聘信息網(wǎng)
C# 事件
1.事件概述
事件(Event) 基本上說(shuō)是一個(gè)用戶操作,如按鍵、點(diǎn)擊、鼠標(biāo)移動(dòng)等等,或者是一些提示信息,如系統(tǒng)生成的通知。應(yīng)用程序需要在事件發(fā)生時(shí)響應(yīng)事件。例如,中斷。
C# 中使用事件機(jī)制實(shí)現(xiàn)線程間的通信。
事件在類中聲明且生成,且通過(guò)使用同一個(gè)類或其他類中的委托與事件處理程序關(guān)聯(lián)。包含事件的類用于發(fā)布事件。這被稱為 發(fā)布器(publisher) 類。其他接受該事件的類被稱為 訂閱器(subscriber) 類。事件使用 發(fā)布-訂閱(publisher-subscriber) 模型。
發(fā)布器(publisher) 是一個(gè)包含事件和委托定義的對(duì)象。事件和委托之間的聯(lián)系也定義在這個(gè)對(duì)象中。發(fā)布器(publisher)類的對(duì)象調(diào)用這個(gè)事件,并通知其他的對(duì)象。
訂閱器(subscriber) 是一個(gè)接受事件并提供事件處理程序的對(duì)象。在發(fā)布器(publisher)類中的委托調(diào)用訂閱器(subscriber)類中的方法(事件處理程序)。
2.使用事件有6個(gè)步驟:
事件處理程序:由訂閱器注冊(cè)到事件的方法,在發(fā)布器觸發(fā)事件時(shí)執(zhí)行。事件處理程序方法可以定義在事件所在的類或結(jié)構(gòu)中,也可以定義在不同的類或結(jié)構(gòu)中。
(1)聲明委托:事件和事件處理程序必須有共同的簽名和返回類型,它們通過(guò)委托類型進(jìn)行描述。
(2)聲明事件:發(fā)布器類必須聲明一個(gè)訂閱器類可以注冊(cè)的事件成員。當(dāng)聲明的事件為public時(shí),稱為發(fā)布了事件。
(3)觸發(fā)事件:發(fā)布器類中“觸發(fā)”事件并導(dǎo)致調(diào)用注冊(cè)的所有事件處理程序的代碼。
(4)聲明事件處理程序:事件處理程序必須具有與事件的委托相同的返回類型和簽名。
(5)訂閱事件并添加或刪除事件處理程序:訂閱者必須訂閱事件才能在它被觸發(fā)時(shí)得到通知。
(6)執(zhí)行觸發(fā)事件語(yǔ)句。
注意點(diǎn):聲明委托、聲明事件、觸發(fā)事件一般放在發(fā)布器類中;
聲明事件處理程序一般放在訂閱器類中;
訂閱事件并添加或刪除事件處理程序可以放在主函數(shù)中也可以放在訂閱器類中
執(zhí)行觸發(fā)事件語(yǔ)句一般放在主函數(shù)中
3.聲明事件:
1.聲明事件代碼
class Incrementer
{
//event 關(guān)鍵字
//EventHandler 是委托類型(委托類型是什么,這里就是什么),.Net框架提供事件使用的標(biāo)準(zhǔn)模式就是System命名空間聲明的EventHandler委托類型(后面會(huì)提到)
//CountedADozen 事件名
public event EventHandler CountedADozen;
}
可以使用逗號(hào)分隔,同時(shí)聲明多個(gè)事件
public event EventHandler myEvent1,myEvent2,myEvent3;
2.注意事項(xiàng)
(1)事件聲明首先需要聲明委托(如果使用默認(rèn)的EventHandler委托類型,就不需要聲明委托了),因?yàn)槁暶魇录枰褂玫轿蓄愋?#xff0c;任何附加到事件的處理程序都必須與委托類型的簽名和返回類型匹配。
(2)事件必須聲明在一個(gè)類中,事件是類或結(jié)構(gòu)的成員,事件成員被隱式自動(dòng)化為null
(3)聲明為public,這樣其他類和結(jié)構(gòu)可以在它上面注冊(cè)事件處理程序。
(4)不能使用對(duì)象創(chuàng)建表達(dá)式(new 表達(dá)式)來(lái)創(chuàng)建它的對(duì)象。
4.訂閱事件:
訂閱者向事件添加事件處理程序,事件處理程序必須具有與事件的委托相同的返回類型和簽名。
使用+=運(yùn)算符來(lái)為事件增加事件處理程序。
事件處理程序的規(guī)范可以是以下任意一種:
實(shí)例方法的名稱;靜態(tài)方法的名稱;委托形式;匿名方法;Lambda表達(dá)式
例如:
//incrementer這個(gè)對(duì)象是發(fā)布器類的對(duì)象
//CountedADozen 是事件名
//IncrementDozensCount 是實(shí)例方法
incrementer.CountedADozen+=IncrementDozensCount;//使用方法引用形式的實(shí)例方法
incrementer.CountedADozen+=ClassB.CounterHandlerB;//使用方法引用形式的靜態(tài)方法
incrementer.CountedADozen+=new EventHandler (cc.CounterHandlerC);//委托形式
incrementer.CountedADozen+=()=>DozensCount++;//Lambda表達(dá)式
incrementer.CountedADozen+=delegate{DozensCount++;}//匿名方法
5.觸發(fā)事件:
在觸發(fā)事件之前和null進(jìn)行比較,從而查看是否包含事件處理程序,如果事件是null,則表示沒(méi)有,不能執(zhí)行。
觸發(fā)事件語(yǔ)法和調(diào)用方法一樣:使用事件名稱,后面跟的參數(shù)列表包含在圓括號(hào)中;參數(shù)列表必須與事件的委托類型相匹配
if(CountedADozen !=null)//確認(rèn)有方法可以執(zhí)行
{
//CountedADozen 事件名
CountedADozen (source,args);//觸發(fā)事件
}
事件聲明和觸發(fā)事件的代碼放在發(fā)布器類中:
6.完整代碼示例:
完整代碼展示如下:發(fā)布器類Incrementer和訂閱器類Dozens,在構(gòu)造函數(shù)中,Dozens類訂閱事件,將Incrementer_CountedADozen作為事件處理程序;在Incrementer類的DoCount方法中,每增長(zhǎng)5個(gè)數(shù)就觸發(fā)CountedADozen事件。
發(fā)布器類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo8_0727
{//1.聲明委托delegate void Handler();//發(fā)布器類internal class Incrementer{public event Handler CountedADozen;//2.聲明事件public void DoCount(){for (int i = 0; i < 100; i++){if (i%5==0&&CountedADozen!=null) //判斷條件{CountedADozen();//3.觸發(fā)事件}} }}
}
訂閱器類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo8_0727
{internal class Dozens{public int DozensCount { get; private set; }public Dozens(Incrementer incrementer ){DozensCount = 0;//5.訂閱事件并添加事件處理程序incrementer.CountedADozen += Incrementer_CountedADozen;}private void Incrementer_CountedADozen()//4.聲明事件處理程序{DozensCount++;}}
}
主函數(shù)類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo8_0727
{internal class Program{static void Main(string[] args){Incrementer incrementer = new Incrementer();Dozens dozens = new Dozens(incrementer);//6.執(zhí)行觸發(fā)事件語(yǔ)句incrementer.DoCount();Console.WriteLine("Number of dozens={0}",dozens.DozensCount);Console.ReadKey();}}
}
7.標(biāo)準(zhǔn)事件用法
.Net框架提供了事件使用的標(biāo)準(zhǔn)模式,.NET 類庫(kù)中的所有事件均基于 EventHandler 委托,定義如下:
public delegate void EventHandler(object sender, EventArgs e);
//第一個(gè)參數(shù)用來(lái)保存觸發(fā)事件的對(duì)象的引用
//第二個(gè)參數(shù)用來(lái)保存狀態(tài)信息,指明什么類型適用于該應(yīng)用程序:
無(wú)需聲明該委托,因?yàn)樗言趧?chuàng)建 C# 項(xiàng)目時(shí)包括的 System 命名空間中聲明。
發(fā)布器類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo9_0727
{internal class Incrementer{//聲明事件public event EventHandler CountedADozen;public void DoCount(){for (int i = 0; i < 100; i++){if (i%5==0&&CountedADozen!=null){//觸發(fā)事件CountedADozen(this,null);}}}}
}
訂閱器類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo9_0727
{internal class Dozens{public int DozensCount { get; private set; }public Dozens(Incrementer incrementer){DozensCount = 0;//訂閱事件并添加事件處理程序incrementer.CountedADozen += Incrementer_CountedADozen;}//聲明事件處理程序private void Incrementer_CountedADozen(object sender, EventArgs e){DozensCount++;}}
}
主函數(shù)類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo9_0727
{internal class Program{static void Main(string[] args){Incrementer incrementer = new Incrementer();Dozens dozens = new Dozens(incrementer);//執(zhí)行觸發(fā)事件語(yǔ)句incrementer.DoCount();Console.WriteLine("Number of dozens={0}",dozens.DozensCount);Console.ReadKey();}}
}
8.通過(guò)擴(kuò)展EventArgs來(lái)傳遞數(shù)據(jù)
如果希望傳遞數(shù)據(jù),必須聲明一個(gè)派生自EventArgs 的類,使用合適的數(shù)據(jù)來(lái)保存需要的數(shù)據(jù)。
為了向自己的事件處理程序的第二個(gè)參數(shù)傳入數(shù)據(jù),需要聲明一個(gè)派生自EventArgs的自定義類,它可以保存我們需要傳入的數(shù)據(jù)。類的名稱應(yīng)該以EventArgs結(jié)尾。
要獲得該類,需要使用泛型委托。(后續(xù)會(huì)提到)
代碼演示:
自定義派生類IncrementerEventArgs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo5_0726
{//自定義派生類繼承EventArgs類internal class IncrementerEventArgs: EventArgs{public int IterationCount { get; set; }//存儲(chǔ)一個(gè)整數(shù)}
}
發(fā)布器類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo5_0726
{internal class Incrementer1{// 聲明事件public event EventHandler<IncrementerEventArgs> CountedADozen;public void DoCount(){ IncrementerEventArgs args=new IncrementerEventArgs();for (int i = 0; i < 100; i++){if (i % 5 == 0 && CountedADozen != null){args.IterationCount = i;CountedADozen(this, args);//在觸發(fā)事件時(shí)傳遞參數(shù)}}}}
}
訂閱器類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo5_0726
{internal class Dozens1{//int _DozensCount;public int DozensCount{get;private set;}public Dozens1(Incrementer1 incrementer1){DozensCount = 0;incrementer1.CountedADozen += Incrementer1_CountedADozen;}private void Incrementer1_CountedADozen(object sender, IncrementerEventArgs e){Console.WriteLine("Incremented at iteration:{0} in {1}",e.IterationCount,sender.ToString());DozensCount++;}}
}
主類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo5_0726
{internal class Program{static void Main(string[] args){Incrementer1 incrementer1 = new Incrementer1();Dozens1 dozens1 = new Dozens1(incrementer1);incrementer1.DoCount();Console.WriteLine("Number of dozens={0}",dozens1.DozensCount);Console.ReadKey(); }}
}