VB.NET下的事件和委托
委托是可用于調(diào)用其他對(duì)象方法的對(duì)象。它們有時(shí)被稱為類型安全函數(shù)指針,因?yàn)樗鼈兣c其他編程語(yǔ)言中所使用的函數(shù)指針相似。但不同于函數(shù)指針,VB.NET 委托是基于 System.Delegate 類的引用類型,它可以引用共享方法—無(wú)需特定的類實(shí)例即可調(diào)用的方法和實(shí)例方法。
委托在調(diào)用過(guò)程和被調(diào)用過(guò)程需要媒介的情況下是很有用的。例如,您可能想讓一個(gè)引發(fā)事件的對(duì)象能夠在不同的環(huán)境下調(diào)用不同的事件處理程序。不幸的是,引發(fā)事件的對(duì)象無(wú)法提前知道處理特定事件的事件處理程序。Visual Basic .NET 通過(guò)在使用 AddHandler 語(yǔ)句時(shí)創(chuàng)建委托,可讓您動(dòng)態(tài)地將事件處理程序與事件關(guān)聯(lián)。在運(yùn)行時(shí),委托將各種調(diào)用轉(zhuǎn)發(fā)到相應(yīng)的事件處理程序。
盡管可以創(chuàng)建自己的委托,但在大多數(shù)情況下,Visual Basic .NET 為您創(chuàng)建委托并提供具體信息。例如,Event 語(yǔ)句將名為 <EventName>EventHandler 的委托類隱式定義為 Event 語(yǔ)句所在類的嵌套類,且其簽字與該事件相同。AddressOf 語(yǔ)句則隱式創(chuàng)建委托的實(shí)例。例如,以下兩行代碼是等效的:
- AddHandler Button1.Click
- AddressOf Me.Button1_Click
- ' AddHandler 指向引發(fā)事件的對(duì)象,AddressOf則確定該事件對(duì)象所要調(diào)用的事件處理程序
- '上述行為又可以稱為 監(jiān)視
- AddHandler Button1.Click, New EventHandler(AddressOf Button1_Click)
只要編譯器可以用上下文確定委托的類型,就可以使用速寫(xiě)方法創(chuàng)建委托。
注:處理自基類繼承的事件
派生類(繼承某個(gè)基類特征的類)能用 Handles MyBase 語(yǔ)句處理它們的基類所引發(fā)的事件。
處理來(lái)自基類的事件
通過(guò)給事件處理程序過(guò)程的聲明行添加 Handles MyBase.<event name> 語(yǔ)句來(lái)聲明派生類中的事件處理程序,其中的 event name 是基類中正在處理的事件的名稱。例如:
- Public Class Class1
- Public Event SE(ByVal i As Integer)
- ' Place methods and properties here.
- End Class
- Public Class Class2
- Inherits Class1
- Sub EventHandler(ByVal x As Integer) Handles MyBase.SE
- ' Place code to handle events from Class1 here.
- End Sub
- End Class
聲明使用現(xiàn)有委托類型的事件
某些情況下,可能會(huì)要聲明某事件使用現(xiàn)有委托類型為基礎(chǔ)委托。以下語(yǔ)法說(shuō)明了進(jìn)行聲明的方式:
Event AnEvent As DelegateType該語(yǔ)法在將多個(gè)事件路由到同一處理程序時(shí)是很有用的,不過(guò)使用現(xiàn)有委托類型時(shí)需要先進(jìn)行如下定義:
- delegate {sub|function} DelegateType(參數(shù)1,參數(shù)2)
下面是vb.net控制臺(tái)程序演示單一事件委托多處理程序.
比如說(shuō)在社會(huì)上,你是法律,社會(huì)上有三種人,警察、無(wú)賴和自愿反扒隊(duì)。
你規(guī)定:如果小偷偷東西,則警察處罰小偷500元錢(qián),自愿反扒隊(duì)要打無(wú)賴進(jìn)醫(yī)院一次
這就是現(xiàn)實(shí)中的委托。
實(shí)際上,在寫(xiě)程序中,程序員就是法律,警察、小偷和自愿反扒隊(duì)就是三個(gè)對(duì)象。小偷偷東西是一個(gè)方法,小偷還有一個(gè)偷東西事件,他偷東西激發(fā)這個(gè)事件。而警察和自愿反扒隊(duì)就是兩個(gè)事件處理對(duì)象,警察負(fù)責(zé)把小偷的錢(qián)扣除500,自愿反扒隊(duì)需要大小偷進(jìn)醫(yī)院一次。
所以,委托有如下幾個(gè)要素:
- 激發(fā)事件的對(duì)象--就是小偷
- 處理對(duì)象事件的對(duì)象--就是警察和自愿反扒隊(duì)
- 定義委托,就是法律讓警察和自愿反扒隊(duì)監(jiān)視小偷。
如果這三個(gè)要素都滿足的話,則你就寫(xiě)出了一個(gè)完整事件的處理。
下面是vb.net控制臺(tái)的實(shí)例
- Imports System
- Module Module1
- '準(zhǔn)備引用 無(wú)賴 類的偷東西事件
- Public WithEvents w As 無(wú)賴
- Sub Main()
- Console.WriteLine("新的一天開(kāi)始了....")
- ' 實(shí)例華警察、無(wú)賴、自愿反扒隊(duì) 類
- Dim p As New 警察
- w = New 無(wú)賴
- Dim pp As New 自愿反扒隊(duì)
- '設(shè)置對(duì)無(wú)賴類的偷東西事件的監(jiān)視,并設(shè)置相應(yīng)的事件處理程序
- '如果小偷玩偷東西則引用警察的罰錢(qián)處理程序
- AddHandler w.PlayGame, AddressOf p.扣錢(qián)
- '如果小偷偷東西則引用自愿反扒隊(duì)的打人處理程序
- AddHandler w.PlayGame, AddressOf pp.打人
- w.偷東西()
- Console.WriteLine("天黑了....")
- Console.ReadLine()
- End Sub
- 'End Class
- Public Class 警察
- Sub New()
- Console.WriteLine("生成警察......")
- End Sub
- '定義的事件處理程序的參數(shù)類型要與定義的委托的參數(shù)類型相一致
- Public Sub 扣錢(qián)(ByVal sender As Object, ByVal e As System.EventArgs)
- Console.WriteLine("警察:好小子,膽敢偷東西...")
- '定義線程輸出遲緩3秒
- System.Threading.Thread.Sleep(3000)
- Console.WriteLine("警察:看看你小子有多少錢(qián)...")
- Dim f As 無(wú)賴 = sender
- System.Threading.Thread.Sleep(3000)
- Console.WriteLine("無(wú)賴 的錢(qián): " + f.錢(qián).ToString())
- System.Threading.Thread.Sleep(3000)
- Console.WriteLine("開(kāi)始扣錢(qián)......")
- System.Threading.Thread.Sleep(3000)
- f.錢(qián) = f.錢(qián) - 500
- Console.WriteLine("扣完了....現(xiàn)在無(wú)賴 還剩下:" + f.錢(qián).ToString())
- System.Threading.Thread.Sleep(3000)
- End Sub
- End Class
- Public Class 無(wú)賴
- '先定義一個(gè)偷東西的事件使用現(xiàn)有委托類型 PlayGameHandler為基礎(chǔ)委托
- Public Event PlayGame As PlayGameHandler
- Private m_Money As Integer
- Private ey As Integer
- Sub New()
- Console.WriteLine("生成無(wú)賴....")
- m_Money = 1000
- ey = 5
- End Sub
- '定義挨打?qū)傩杂脕?lái)記錄挨打過(guò)幾次
- Property 挨打() As Integer
- Get
- Return ey
- End Get
- Set(ByVal Value As Integer)
- ey = Value
- End Set
- End Property
- '定義前屬性用來(lái)記錄有多少錢(qián)
- Property 錢(qián)() As Integer
- Get
- Return m_Money
- End Get
- Set(ByVal Value As Integer)
- m_Money = Value
- End Set
- End Property
- '定義偷東西過(guò)程
- Public Sub 偷東西()
- Console.WriteLine("無(wú)賴開(kāi)始偷東西了")
- System.Threading.Thread.Sleep(3000)
- '實(shí)例化事件參數(shù)
- Dim e As New System.EventArgs
- '引發(fā)偷東西事件,參數(shù)類型要與現(xiàn)有委托類型一致
- RaiseEvent PlayGame(Me, e)
- End Sub
- End Class
- Public Class 自愿反扒隊(duì)
- Sub New()
- Console.WriteLine("自愿反扒隊(duì)來(lái)了.....")
- System.Threading.Thread.Sleep(3000)
- End Sub
- '定義的事件處理程序的參數(shù)類型要與定義的委托的參數(shù)類型相一致
- Public Sub 打人(ByVal sender As Object, ByVal e As System.EventArgs)
- System.Threading.Thread.Sleep(3000)
- Console.WriteLine("自愿反扒隊(duì):好小子,敢偷東西...")
- System.Threading.Thread.Sleep(3000)
- Console.WriteLine("自愿反扒隊(duì):你小子挨過(guò)幾次打了...")
- Dim bn As 無(wú)賴 = sender
- System.Threading.Thread.Sleep(3000)
- Console.WriteLine("無(wú)賴:" + bn.挨打.ToString + "次")
- System.Threading.Thread.Sleep(3000)
- Console.WriteLine("自愿反扒隊(duì):那也得揍你,先來(lái)一拳.... ")
- System.Threading.Thread.Sleep(3000)
- Console.WriteLine("自愿反扒隊(duì):再來(lái)一腳......")
- System.Threading.Thread.Sleep(3000)
- Console.WriteLine("自愿反扒隊(duì):打完了...趕緊去醫(yī)院吧...")
- End Sub
- End Class
- '定義委托類型
- Delegate Sub PlayGameHandler(ByVal sender As Object, ByVal e As System.EventArgs)
- End Module
進(jìn)一步閱讀:談JavaScript中的事件委托
【編輯推薦】