1. 程式人生 > >VB.NET下的事件和委託

VB.NET下的事件和委託

委託是可用於呼叫其他物件方法的物件。它們有時被稱為型別安全函式指標,因為它們與其他程式語言中所使用的函式指標相似。但不同於函式指標,Visual Basic .NET 委託是基於 System.Delegate 類的引用型別,它可以引用共享方法 —無需特定的類例項即可呼叫的方法和例項方法。

委託在呼叫過程和被呼叫過程需要媒介的情況下是很有用的。例如,您可能想讓一個引發事件的物件能夠在不同的環境下呼叫不同的事件處理程式。不幸的是,引發事件的物件無法提前知道處理特定事件的事件處理程式。Visual Basic .NET 通過在使用 AddHandler 語句時建立委託,可讓您動態地將事件處理程式與事件關聯。在執行時,委託將各種呼叫轉發到相應的事件處理程式。

儘管可以建立自己的委託,但在大多數情況下,Visual Basic .NET 為您建立委託並提供具體資訊。例如,Event 語句將名為 <EventName>EventHandler 的委託類隱式定義為 Event 語句所在類的巢狀類,且其簽字與該事件相同。AddressOf 語句則隱式建立委託的例項。例如,以下兩行程式碼是等效的:

AddHandler Button1.Click, AddressOf Me.Button1_Click
   ' AddHandler 指向引發事件的物件,AddressOf則確定該事件物件所要呼叫的事件處理程式
'上述行為又可以稱為 監 視 AddHandler Button1.Click, New EventHandler(AddressOf Button1_Click)

只要編譯器可以用上下文確定委託的型別,就可以使用速寫方法建立委託。
注:處理自基類繼承的事件
派生類(繼承某個基類特徵的類)能用 Handles MyBase 語句處理它們的基類所引發的事件。
處理來自基類的事件
通過給事件處理程式過程的宣告行新增 Handles MyBase.<event name> 語句來宣告派生類中的事件處理程式,其中的 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

宣告使用現有委託型別的事件

某些情況下,可能會要宣告某事件使用現有委託型別為基礎委託。以下語法說明了進行宣告的方式:

Event AnEvent As DelegateType

該語法在將多個事件路由到同一處理程式時是很有用的,不過使用現有委託型別時需要先進行如下定義:
delegate  {sub|function} DelegateType(引數1,引數2)
下面是vb.net控制檯程式演示單一事件委託多處理程式.  
  比如說在社會上,你是法律,社會上有三種人,警察、無賴和自願反扒隊。  
  你規定:如果小偷偷東西,則警察處罰小偷500元錢,自願反扒隊要打無賴進醫院一次
    
  這就是現實中的委託。  
   
  實際上,在寫程式中,程式設計師就是法律,警察、小偷和自願反扒隊就是三個物件。小偷偷東西是一個方法,小偷還有一個偷東西事件,他偷東西激發這個事件。而警察和自願反扒隊就是兩個事件處理物件,警察負責把小偷的錢扣除500,自願反扒隊需要大小偷進醫院一次。
    
  所以,委託有如下幾個要素:  
  1   激發事件的物件--就是小偷   
  2   處理物件事件的物件--就是警察和自願反扒隊 
  3   定義委託,就是法律讓警察和自願反扒隊監視小偷。  
   
  如果這三個要素都滿足的話,則你就寫出了一個完整事件的處理。
下面是vb.net控制檯的例項
Imports System
Module Module1
    '準備引用 無賴 類的偷東西事件
    Public WithEvents w As 無賴
    Sub Main()
        Console.WriteLine("新的一天開始了....")
        ' 例項華警察、無賴、自願反扒隊 類
        Dim p As New 警察
        w = New 無賴
        Dim pp As New 自願反扒隊
        '設定對無賴類的偷東西事件的監視,並設定相應的事件處理程式
        '如果小偷玩偷東西則引用警察的罰錢處理程式
        AddHandler w.PlayGame, AddressOf p.扣錢
        '如果小偷偷東西則引用自願反扒隊的打人處理程式
        AddHandler w.PlayGame, AddressOf pp.打人
        w.偷東西()
        Console.WriteLine("天黑了....")
        Console.ReadLine()
    End Sub
    '  End Class


    Public Class 警察
        Sub New()
            Console.WriteLine("生成警察......")
        End Sub
        '定義的事件處理程式的引數型別要與定義的委託的引數型別相一致
        Public Sub 扣錢(ByVal sender As Object, ByVal e As System.EventArgs)

            Console.WriteLine("警察:好小子,膽敢偷東西...")
            '定義執行緒輸出遲緩3秒
            System.Threading.Thread.Sleep(3000)
            Console.WriteLine("警察:看看你小子有多少錢...")
            Dim f As 無賴 = sender
            System.Threading.Thread.Sleep(3000)
            Console.WriteLine("無賴 的錢:   " + f.錢.ToString())
            System.Threading.Thread.Sleep(3000)
            Console.WriteLine("開始扣錢......")
            System.Threading.Thread.Sleep(3000)
            f.錢 = f.錢 - 500
            Console.WriteLine("扣完了....現在無賴 還剩下:" + f.錢.ToString())
            System.Threading.Thread.Sleep(3000)
        End Sub

    End Class
    Public Class 無賴
        '先定義一個偷東西的事件使用現有委託型別 PlayGameHandler為基礎委託
        Public Event PlayGame As PlayGameHandler
        Private m_Money As Integer
        Private ey As Integer
        Sub New()
            Console.WriteLine("生成無賴....")
            m_Money = 1000
            ey = 5
        End Sub
        '定義捱打屬性用來記錄捱打過幾次
        Property 捱打() As Integer
            Get
                Return ey
            End Get
            Set(ByVal Value As Integer)
                ey = Value
            End Set
        End Property
        '定義前屬性用來記錄有多少錢
        Property 錢() As Integer
            Get
                Return m_Money
            End Get
            Set(ByVal Value As Integer)
                m_Money = Value
            End Set
        End Property
        '定義偷東西過程
        Public Sub 偷東西()
            Console.WriteLine("無賴開始偷東西了")
            System.Threading.Thread.Sleep(3000)
            '例項化事件引數
            Dim e As New System.EventArgs
            '引發偷東西事件,引數型別要與現有委託型別一致
            RaiseEvent PlayGame(Me, e)
        End Sub
    End Class
    Public Class 自願反扒隊
        Sub New()
            Console.WriteLine("自願反扒隊來了.....")
            System.Threading.Thread.Sleep(3000)
        End Sub
        '定義的事件處理程式的引數型別要與定義的委託的引數型別相一致
        Public Sub 打人(ByVal sender As Object, ByVal e As System.EventArgs)
            System.Threading.Thread.Sleep(3000)
            Console.WriteLine("自願反扒隊:好小子,敢偷東西...")
            System.Threading.Thread.Sleep(3000)
            Console.WriteLine("自願反扒隊:你小子捱過幾次打了...")
            Dim bn As 無賴 = sender
            System.Threading.Thread.Sleep(3000)
            Console.WriteLine("無賴:" + bn.捱打.ToString + "次")
            System.Threading.Thread.Sleep(3000)

            Console.WriteLine("自願反扒隊:那也得揍你,先來一拳....   ")
            System.Threading.Thread.Sleep(3000)
            Console.WriteLine("自願反扒隊:再來一腳......")
            System.Threading.Thread.Sleep(3000)

            Console.WriteLine("自願反扒隊:打完了...趕緊去醫院吧...")
        End Sub
    End Class
    '定義委託型別
    Delegate Sub PlayGameHandler(ByVal sender As Object, ByVal e As System.EventArgs)
End Module