目錄?
l????????導(dǎo)論?
l????????什么是委托?
l????????事件的理解?
l????????事件 關(guān)鍵字?
l????????最后?
??
導(dǎo)論?
????在學(xué)習(xí)c#中的委托和事件過程中,我讀了許多文章來理解他們二者究竟是怎么一回事,以及如何使用他們,現(xiàn)在我將整個(gè)的理解過程陳述以下,我學(xué)到的每一方面,恐怕也是你們需要掌握的 :-)。?
什么是委托??
????委托和事件這兩個(gè)概念是完全配合的。委托僅僅是函數(shù)指針,那就是說,它能夠引用函數(shù),通過傳遞地址的機(jī)制完成。委托是一個(gè)類,當(dāng)你對(duì)它實(shí)例化時(shí),要提供一個(gè)引用函數(shù),將其作為它構(gòu)造函數(shù)的參數(shù)。?
??每一個(gè)委托都有自己的簽名,例如:delegate int somedelegate(string s, bool b);是一個(gè)委托申明,在這里,提及的簽名,就是說somedelegate 這個(gè)委托 有 string 和 bool 類型的形參,返回一個(gè)int 類型。?
上面提及的:當(dāng)你對(duì)委托實(shí)例化時(shí),要提供一個(gè)引用函數(shù),將其作為它構(gòu)造函數(shù)的參數(shù)。這里要注意了:被引用的這個(gè)函數(shù)必須和委托有相同的簽名。?
看下面的函數(shù):?
private int somefunction(string str, bool bln){...}?
你可以把這個(gè)函數(shù)傳給somedelegate的構(gòu)造函數(shù),因?yàn)樗麄冇邢嗨频暮灻╥n other?words,他們都有相同的形參類型和個(gè)數(shù),并且返回相同的數(shù)據(jù)類型)。?
????somedelegate sd = new somedelegate(somefunction);?
??sd 引用了 somefunction,也就是說,somefunction已被sd所登記注冊(cè),如果你調(diào)用 sd,somefunction 這個(gè)函數(shù)也會(huì)被調(diào)用,記?。何宜f somefunction的含義,后面,我們會(huì)用到它。?
??現(xiàn)在,你應(yīng)該知道如何使用委托了,讓我們繼續(xù)理解事件之旅……?
事件的理解?
我們知道,在c#中:?
l????????按鈕(button)就是一個(gè)類,當(dāng)我們單擊它時(shí),就觸發(fā)一次click事件。?
l????????時(shí)鐘(timer)也是一個(gè)類,每過一毫秒,就觸發(fā)一次tick事件。?
讓我們通過一個(gè)例子來學(xué)習(xí),假定有這樣的情節(jié):?
??現(xiàn)在有一個(gè)counter的類,它有一個(gè)方法 countto(int countto, int reachablenum),該方法表示:在指定的時(shí)間段內(nèi)(0~~countto),當(dāng)?shù)竭_(dá)指定的時(shí)間點(diǎn)reachablenum時(shí),就觸發(fā)一次numberreached事件。?
它還有一個(gè)事件:numberreached,事件是委托類型的變量。意思是:如果給事件命名,用event關(guān)鍵字和要使用的委托類型申明它即可,如下所示:?
public event numberreachedeventhandler numberreached;?
??
在上面的申明中,numberreachedeventhandle 僅是一個(gè)委托,更確切的表示應(yīng)該是:numberreacheddelegate。但是微軟從不這樣認(rèn)為mousedelegate或者paintdelegate,,而是稱謂:mouseeventhandler 或者 painteventhandler。所以?
numberreachedeventhandler 比numberreacheddelegate聽起來更方便一些,ok?好了,讓我們繼續(xù),現(xiàn)在你知道了,在我們聲明事件之前,需要象下面這樣的形式來定義委托:?
public delegate void numberreachedeventhandler(object sender, numberreachedeventargs e);?
現(xiàn)在聲明的委托 numberreachedeventhandle,它有一個(gè)void 返回值,和object,numberreachedeventargs兩個(gè)形參。就像我們?cè)诘谝还?jié)中強(qiáng)調(diào)的那樣,當(dāng)實(shí)例化委托時(shí),作為實(shí)參傳入的函數(shù)也必須擁有和委托同樣的簽名。?
在你的代碼中, 你是否用過painteventargs 或者 mouseeventargs來確定鼠標(biāo)的移動(dòng)位置?是否在觸發(fā)paint事件的對(duì)象中用過graphics 屬性?實(shí)際上,為用戶提供數(shù)據(jù)的類都是繼承于system.eventargs類,就是我們常說的事件參數(shù)類,如果事件不提供參數(shù),就不定義該類。在我們的例子中,我們通過下面的類提供預(yù)期的時(shí)間點(diǎn)。?
public class numberreachedeventargs : eventargs?
{?
????private int _reached;?
????public numberreachedeventargs(int num)?
????{?
????????this._reached = num;?
????}?
????public int reachednumber?
????{?
????????get?
????????{?
????????????return _reached;?
????????}?
????}?
}?
好,有了前面的介紹,讓我們到counter類里面看看:?
namespace events?
{?
????public delegate void numberreachedeventhandler(object sender,?
????????numberreachedeventargs e);?
??
????///
????/// summary description for counter.?
????///
????public class counter?
????{?
????????public event numberreachedeventhandler numberreached;?
????????
????????public counter()?
????????{?
????????????//?
????????????// todo: add constructor logic here?
????????????//?
????????}?
????????public void countto(int countto, int reachablenum)?
????????{?
????????????if(countto
????????????????throw new argumentexception(?
????????????????????"reachablenum should be less than countto");?
????????????for(int ctr=0;ctr
????????????{?
????????????????if(ctr == reachablenum)?
????????????????{?
????????????????????numberreachedeventargs e = new numberreachedeventargs(?
????????????????????????reachablenum);?
????????????????????onnumberreached(e);?
????????????????????return;//don't count any more?
????????????????}?
????????????}?
????????}?
??
????????protected virtual void onnumberreached(numberreachedeventargs e)?
????????{?
????????????if(numberreached != null)?
????????????{?
????????????????numberreached(this, e);//raise the event?
????????????}?
????????}?
}?
在counter中,如果到達(dá)指定的時(shí)間點(diǎn),就觸發(fā)一次事件,有以下幾個(gè)方面需要注意:?
l????????通過調(diào)用numberreached(它是numberreachedeventhandler委托的實(shí)例)來完成一次觸發(fā)事件。?
numberreached(this, e);??通過這種方式,可以調(diào)用所有的注冊(cè)函數(shù)。?
l????????通過 numberreachedeventargs e = new numberreachedeventargs(reachablenum); 為所有的注冊(cè)函數(shù)提供事件數(shù)據(jù)。?
l????????看了上面的代碼,你可能要問了:為什么我們直接用 onnumberreached(numberreachedeventargs e)方法來調(diào)用numberreached(this,e),而不用下面的代碼呢??
????if(ctr == reachablenum)?
{?
????numberreachedeventargs e = new numberreachedeventargs(reachablenum);?
????//onnumberreached(e);?
????if(numberreached != null)?
????{?
????????numberreached(this, e);//raise the event?
????}?
????return;//don't count any more?
}?
這個(gè)問題問得很好,那就讓我們?cè)倏匆幌耾nnumberreached 簽名:?
protected virtual void onnumberreached(numberreachedeventargs e)?
①你也明白 關(guān)鍵字protected限定了 只有從該類繼承的類才能調(diào)用該類中的所有方法。?
②關(guān)鍵字 virtual 表明了 在繼承類中可以重寫該方法。?
這兩點(diǎn)非常有用,假設(shè)你在寫一個(gè)從counter繼承而來的類,通過重寫onnumberreached 方法,你可以在事件觸發(fā)之前,進(jìn)行一次其他的工作。?
??
protected override void onnumberreached(numberreachedeventargs e)?
{?
????//do additional work?
????base.onnumberreached(e);?
}?
注意:如果你沒有調(diào)用base.onnumberreached(e), 那么從不會(huì)觸發(fā)這個(gè)事件!在你繼承該類而想剔出它的一些其他事件時(shí),使用該方式是非常有用的。?
l????????還要注意到:委托 numberreachedeventhandler 是在類定義的外部,命名空間內(nèi)定義的,對(duì)所有類來說是可見的。?
好,該我們來實(shí)際操作使用counter類了。?
??
在我們簡(jiǎn)單的應(yīng)用程序中,我們有兩個(gè)文本框,分別是:txtcountto和txtreachable:?
下面是btnrun的click事件:?
private void btnrun_click(object sender, system.eventargs e)?
???????{?
???????????if(txtcountto.text == "" || txtreachable.text=="")?
??????????????return;?
???????????ocounter.countto(convert.toint32(txtcountto.text), convert.toint32(txtreachable.text));?
???????}?
??
private void ocounter_numberreached(object sender, numberreachedeventargs e)?
???????{?
???????????messagebox.show("reached: " + e.reachednumber.tostring());?
???}?
??
初始化事件處理的語法如下:?
ocounter = new counter();?
??????????ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached);?
??????????
現(xiàn)在你明白了你剛才所做的一切,僅僅初始化 numberreachedeventhandler 委托類型的對(duì)象(就像你實(shí)例化其他對(duì)象一樣),注意到 ocounter_numberreached 方法的簽名與我前面提到的相似。?
還要注意我們用的是+= 而不是=;這是因?yàn)槲惺翘厥獾膶?duì)象,它可以引用多個(gè)對(duì)象(在這里是指它可以引用多個(gè)函數(shù))。for example 如果有另外一個(gè)?
和ocounter_numberreached一樣具有相同簽名的函數(shù)ocounter_numberreached2,這兩個(gè)函數(shù)都可以被引用:?
??
ocounter = new counter();?
???????????ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached);?
???????????ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached2);?
現(xiàn)在,觸發(fā)一個(gè)事件后,上面兩個(gè)函數(shù)被依次調(diào)用。?
??
視情況而定,如果你想讓ocounter_numberreached2在numberreached事件發(fā)生后不再被調(diào)用,可以簡(jiǎn)單地這樣寫:ocounter.numberreached -= new numberreachedeventhandler(ocounter_numberreached2);?
??
最后???讓我們看一下完整的源代碼,以供參考:?
form1.cs?
using system;?
using system.drawing;?
using system.collections;?
using system.componentmodel;?
using system.windows.forms;?
using system.data;?
namespace events?
{?
????/**////
????/// summary description for form1.?
????///
????public class form1 : system.windows.forms.form?
????{?
????????counter ocounter = null;?
????????private system.windows.forms.button cmdrun;?
????????private system.windows.forms.textbox txtreachable;?
????????private system.windows.forms.textbox txtcountto;?
????????private system.windows.forms.label label1;?
????????private system.windows.forms.label label2;?
????????private system.windows.forms.button btnremovedelegate;?
????????/**////
????????/// required designer variable.?
????????///
????????private system.componentmodel.container components = null;?
????????public form1()?
????????{?
????????????//?
????????????// required for windows form designer support?
????????????//?
????????????initializecomponent();?
????????????//?
????????????// todo: add any constructor code after initializecomponent call?
????????????//?
????????????ocounter = new counter();?
????????????ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached);?
????????????ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached2);?
????????}?
????????/**////
????????/// clean up any resources being used.?
????????///
????????protected override void dispose( bool disposing )?
????????{?
????????????if( disposing )?
????????????{?
????????????????if (components != null)??
????????????????{?
????????????????????components.dispose();?
????????????????}?
????????????}?
????????????base.dispose( disposing );?
????????}?
????????windows form designer generated code#region windows form designer generated code?
????????/**////
????????/// required method for designer support - do not modify?
????????/// the contents of this method with the code editor.?
????????///
????????private void initializecomponent()?
????????{?
????????????this.cmdrun = new system.windows.forms.button();?
????????????this.txtreachable = new system.windows.forms.textbox();?
????????????this.txtcountto = new system.windows.forms.textbox();?
????????????this.label1 = new system.windows.forms.label();?
????????????this.label2 = new system.windows.forms.label();?
????????????this.btnremovedelegate = new system.windows.forms.button();?
????????????this.suspendlayout();?
????????????//??
????????????// cmdrun?
????????????//??
????????????this.cmdrun.location = new system.drawing.point(16, 72);?
????????????this.cmdrun.name = "cmdrun";?
????????????this.cmdrun.size = new system.drawing.size(48, 23);?
????????????this.cmdrun.tabindex = 2;?
????????????this.cmdrun.text = "run";?
????????????this.cmdrun.click += new system.eventhandler(this.cmdrun_click);?
????????????//??
????????????// txtreachable?
????????????//??
????????????this.txtreachable.location = new system.drawing.point(144, 40);?
????????????this.txtreachable.name = "txtreachable";?
????????????this.txtreachable.size = new system.drawing.size(56, 20);?
????????????this.txtreachable.tabindex = 1;?
????????????this.txtreachable.text = "";?
????????????//??
????????????// txtcountto?
????????????//??
????????????this.txtcountto.location = new system.drawing.point(144, 16);?
????????????this.txtcountto.name = "txtcountto";?
????????????this.txtcountto.size = new system.drawing.size(56, 20);?
????????????this.txtcountto.tabindex = 0;?
????????????this.txtcountto.text = "";?
????????????//??
????????????// label1?
????????????//??
????????????this.label1.autosize = true;?
????????????this.label1.location = new system.drawing.point(16, 16);?
????????????this.label1.name = "label1";?
????????????this.label1.size = new system.drawing.size(51, 13);?
????????????this.label1.tabindex = 3;?
????????????this.label1.text = "count to";?
????????????//??
????????????// label2?
????????????//??
????????????this.label2.autosize = true;?
????????????this.label2.location = new system.drawing.point(16, 40);?
????????????this.label2.name = "label2";?
????????????this.label2.size = new system.drawing.size(99, 13);?
????????????this.label2.tabindex = 4;?
????????????this.label2.text = "reach this number";?
????????????//??
????????????// btnremovedelegate?
????????????//??
????????????this.btnremovedelegate.location = new system.drawing.point(16, 104);?
????????????this.btnremovedelegate.name = "btnremovedelegate";?
????????????this.btnremovedelegate.size = new system.drawing.size(168, 23);?
????????????this.btnremovedelegate.tabindex = 5;?
????????????this.btnremovedelegate.text = "remove second handler";?
????????????this.btnremovedelegate.click += new system.eventhandler(this.btnremovedelegate_click);?
????????????//??
????????????// form1?
????????????//??
????????????this.autoscalebasesize = new system.drawing.size(5, 13);?
????????????this.clientsize = new system.drawing.size(224, 134);?
????????????this.controls.addrange(new system.windows.forms.control[] {?
??????????????????????????????????????????????????????????????????????????this.btnremovedelegate,?
??????????????????????????????????????????????????????????????????????????this.label2,?
??????????????????????????????????????????????????????????????????????????this.label1,?
??????????????????????????????????????????????????????????????????????????this.txtcountto,?
??????????????????????????????????????????????????????????????????????????this.txtreachable,?
??????????????????????????????????????????????????????????????????????????this.cmdrun});?
????????????this.name = "form1";?
????????????this.text = "events";?
????????????this.resumelayout(false);?
????????}?
????????#endregion?
????????/**////
????????/// the main entry point for the?application.?
????????///
????????[stathread]?
????????static void main()??
????????{?
????????????application.run(new form1());?
????????}?
????????private void btnrun_click(object sender, system.eventargs e)?
????????{?
????????????if(txtcountto.text == "" || txtreachable.text=="")?
????????????????return;?
????????????ocounter.countto(convert.toint32(txtcountto.text), convert.toint32(txtreachable.text));?
????????}?
????????private void ocounter_numberreached(object sender, numberreachedeventargs e)?
????????{?
????????????messagebox.show("reached: " + e.reachednumber.tostring());?
????????}?
????????private void ocounter_numberreached2(object sender, numberreachedeventargs e)?
????????{?
????????????messagebox.show("reached2: " + e.reachednumber.tostring());?
????????}?
????????private void btnremovedelegate_click(object sender, system.eventargs e)?
????????{?
????????????ocounter.numberreached -= new numberreachedeventhandler(ocounter_numberreached2);?
????????????ocounter.countto(convert.toint32(txtcountto.text), convert.toint32(txtreachable.text));?
????????}?
????}?
}?
??
counter.cs?
??
using system;?
namespace events?
{?
????public delegate void numberreachedeventhandler(object sender, numberreachedeventargs e);?
????/**////
????/// summary description for counter.?
????///
????public class counter?
????{?
????????public event numberreachedeventhandler numberreached;?
?????????
????????public counter()?
????????{?
????????????//?
????????????// todo: add constructor logic here?
????????????//?
????????}?
????????public void countto(int countto, int reachablenum)?
????????{?
????????????if(countto ????????????????throw new argumentexception("reachablenum should be less than countto");?
????????????for(int ctr=0;ctr????????????{?
????????????????if(ctr == reachablenum)?
????????????????{?
????????????????????numberreachedeventargs e = new numberreachedeventargs(reachablenum);?
????????????????????onnumberreached(e);?
????????????????????return;//don't count any more?
????????????????}?
????????????}?
????????}?
????????protected virtual void onnumberreached(numberreachedeventargs e)?
????????{?
????????????if(numberreached!=null)?
????????????{?
????????????????numberreached(this, e);?
????????????}?
????????}?
????}?
????public class numberreachedeventargs : eventargs?
????{?
????????private int _reached;?
????????public numberreachedeventargs(int num)?
????????{?
????????????this._reached = num;?
????????}?
????????public int reachednumber?
????????{?
????????????get?
????????????{?
????????????????return _reached;?
????????????}?
????????}?
????}?
}?
?以上就是C#委托,事件理解入門的內(nèi)容,更多相關(guān)內(nèi)容請(qǐng)關(guān)注PHP中文網(wǎng)(www.miracleart.cn)!?
每個(gè)人都需要一臺(tái)速度更快、更穩(wěn)定的 PC。隨著時(shí)間的推移,垃圾文件、舊注冊(cè)表數(shù)據(jù)和不必要的后臺(tái)進(jìn)程會(huì)占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號(hào)
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://www.miracleart.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號(hào)