1. 程式人生 > >VB.net學習筆記(七)物件事件的定製

VB.net學習筆記(七)物件事件的定製

物件還有一個重要的特性:事件

根據需要呼叫指定的功能,與物件互動作用。即:在執行過程中某動作發生後,給物件提供通知。

物件引發自己的事件,通過這個機制通知客戶端程式碼執行了重要的操作或事件。

VB.net中,可用Net委託機制提供事件支援。

1、事件處理

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      這是Button控制元件的Click事件。注意上面兩個地方:

             一、Handles   Button1.Click          表明這個方法應處理Button1中的Click事件。

                     Handles的目的就是把這個方法與Button類中的Click事件關聯起來。

             二、兩個引數。這是因為控制元件類定義了這些引數(引數的個數、型別)。如果引數不對將引發錯誤。

      方法名Button1_Click,這無關痛癢,可以是其它名,例如:

Private Sub AAAAAXXXXX(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

       上面用AAAAXXXXX,事件一樣生效,所以方法名是不重要的。

       所以更改方法名,只要後面的引數及Handles正確,一樣正常。

2、處理多個事件

      Handles關鍵字提供了靈活的關聯,它可以關聯多個事件,這多個事件可用逗號隔開,每個事件都會導致方法執行。

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click,Button2.Click

     上面的寫法,唯一的要求是,每個事件的引數個數及型別必須是相同的。

       要注意的是方法可以由多個事件引發,一個事件也可以引發多個方法。

  
3、WithEvents

      WithEvents告訴VB.net,要處理物件所引發的任何事件。如果不帶這個關鍵字,那麼這個物件即使有事件,也不會引發。這正如英文的意思一樣。

     另一種情況,如果物件本身定義中不能引發事件,如果強行用WithEvents將會引發語法錯誤。

      VB.net通過檢查介面,編譯器可以確定哪些類引發事件,哪些類不引發事件。任何引發事件的類都會將該事件宣告

      為介面的一部分。因此,用了WithEvents,就意味著使用Event(它將在類中宣告哪些是事件)

4、觸發事件

      我們使用事件的目的,就是觸發事件。因此,我們之前應做好事件的定義、引發、接收等事件前期工作。

      首先應在類中定義好事件:用Event說明哪個是事件,用RaiseEvent來激發事件。

      在客戶端使用好事件:用WithEvents來說明要用這個事件,用Hanldes來接收、響應事件。如圖:


      在定義中相當於定義警鈴一樣,1、定義事件(哪個是警鈴,是否帶引數)

      然後,在方法處理中啟用事件(激響警鈴)

      在客戶使用中,用WithEvents來說明要用警鈴了,再用hanldes關聯到一個方法中。

      所以RaiseEvent引發事件的,用hanldes關聯的方法作為接收器來接收事件。

       Handles就是一件貨物打了標籤一樣,到死都是這個標籤,不能更改。因此,只要關聯某方法後,就會一直關聯。

       另外,如果接收的方法不止一個時,每次將一個事件傳到一個接收器中,預設下,不能預測預測接收器接收事件的順序。

        但,事件必須傳遞到所有處理程式中。這是一個連續且同步的過程,若一旦呼叫RaiseEvents,將無法干涉終止這個過程。

5、宣告、觸發定製事件

      預設下,無法控制事件的觸發方式。

      為了突破這個限制,使用一種更加顯式的事件宣告形式,而不再用簡單的Event來宣告。這就是定製事件。

      委託,生活中常見的委託人,委託某人辦某事,就是此意。

      委託,委託,就是你辦不了事情,委託別人去辦... 對計算機來說,計算機執行緒外的東西,是沒辦法直接被執行緒呼叫的

      為了能讓執行緒執行呼叫不到的事件,那就建立委託吧
       委託就產生了           先定義一個委託體:Delegate Sub SetTxtOutputCallback(ByVal ksks As String)
         委託了,就不會衝突了

        下面是各部分的程式碼,先定義一個事件的委託,然後定義一個變數用來跟蹤偵聽的變數,然後定製事件儲存與觸發(結構)

Public Delegate Sub WalkedEventHandler(ByVal distance As Int32)

Private mWalkedHandlers As WalkedEventHandler

Public Custom Event Walked As WalkedEventHandler

    AddHandler(ByVal value As WalkedEventHandler)
        mWalkedhandlers = CType([delegate].combine(mWalkedhandlers, value), _WalkedEventHandler)
    End AddHandler

    RemoveHandler(ByVal value As WalkedEventHandler)
        mwalkedhandlers = CType([delegate].remove(mWalkedHandlers, value), WalkedEventHandler)
    End RemoveHandler

    RaiseEvent(ByVal distance As Integer)
        If mWalkedHandlers isnot Nothing thdn
            mWalkedHandlers.invoke(distance)
        End If
    End RaiseEvent

End Event

          上面AddHandler用於新增一個新處理程式。

                  RemoveHandler用於停止接收事件的某個事件處理程式

                  RaiseEvent 觸發呼叫事件。

6、WithEvents

      它宣告要接收該物件引發的任何事件。如果沒有用WithEvents不會出錯,但不會接收該物件中的事件。

      當我們引發事件RaiseEvent時,可能誤認為是由多執行緒來完成的,其實不然,這個過程只是一個執行緒,       引發事件類似呼叫方法,正如呼叫函式一樣,返回後再繼續向下執行。       下面執行的順序是:1234567


7、動態的增加接收事件和取消事件

     前面的WithEvents和Handles就象難兄弟一樣,成對出現,而且他們是死結,一旦出現無法取消,就象死咒一樣。

     為了適應靈活的情況,可以不用上面,而使用另一對靈動的兄弟AddHanlder和RemoveHanlder。

      AddHanlder可以動態地新增事件處理程式,RemoveHanlder可以動態地刪除事件處理程式。

       因為這種連結是在執行時建立的,能夠更多地控制過程(比如加入判斷,達到要求就可建立連結,否則沒有連結)

Public Class Form1

    Private mobjPerson As Person

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        mobjPerson = New Person()
        AddHandler mobjPerson.Walked, AddressOf OnWalk '動態加入事件(作用與withEvents與Handles連結類似)
    End Sub

    Private Sub OnWalk(ByVal Distance As Integer)
        MessageBox.Show("Person walked " & Distance)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        mobjPerson.Walk(42)
    End Sub

End Class


Public Class Person
    Private mintTotalDistance As Integer
    Public Event Walked(ByVal Distance As Integer)

    Public Sub Walk(ByVal Distance As Integer)
        mintTotalDistance += Distance
        RaiseEvent Walked(Distance)
    End Sub

End Class

           注意:如果不將事件處理程式與事件分離(RemoveHanlder),物件將保留在記憶體中,即使上面mobjPerson不再指向物件,每個事件仍有物件的一個引用。

                       所以AddHandler與RemoveHandler必須成對出現,不然易出現記憶體洩露。而WithEvents會自動處理這些細節。

              下面是不同情況加入不同的連結:

Public Class Form1

    Private mobjPerson As Person

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        mobjPerson = New Person()
        If Microsoft.VisualBasic.Command = "nodisplay" Then '檢測IDE中命令列是否為nodiaplay
            AddHandler mobjPerson.Walked, AddressOf LongOnWalk '關聯一個事件
        Else
            AddHandler mobjPerson.Walked, AddressOf OnWalk     '關聯另一個事件
        End If
    End Sub

    Private Sub OnWalk(ByVal Distance As Integer)
        MessageBox.Show("Person walked " & Distance)
    End Sub

    Private Sub LongOnWalk(ByVal Distance As Integer)
        System.Diagnostics.Debug.WriteLine("Person walked" & Distance)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        mobjPerson.Walk(42)
    End Sub

End Class


Public Class Person
    Private mintTotalDistance As Integer
    Public Event Walked(ByVal Distance As Integer)

    Public Sub Walk(ByVal Distance As Integer)
        mintTotalDistance += Distance
        RaiseEvent Walked(Distance)
    End Sub

End Class

           同樣,分離這種關係時,也應對應著分離:
        If Microsoft.VisualBasic.Command = "nodisplay" Then
            RemoveHandler mobjPerson.Walked, AddressOf LongOnWalk
        Else
            RemoveHandler mobjPerson.Walked, AddressOf OnWalk
        End If
        mobjPerson = New Person


8、建構函式

      這個C++老講,不再說了。

      VB.net用New做建構函式,在物件產生時進行初始化,對每個物件它只執行一次。

      不帶引數的New:

  Public Sub New()
    Phone("home") = "555-1234"
    Phone("work") = "555-5678"
  End Sub


        帶引數的New:

  Public Sub New(ByVal Name As String, ByVal BirthDate As Date)
    mstrName = Name
    mdtBirthDate = BirthDate
    Phone("home") = "555-1234"
    Phone("work") = "555-5678"
  End Sub


       類中可以有幾個New建構函式,它們可以過載。當使用時智慧會提示有幾個New函式,如下面提示有2個


9、釋放物件

       釋放物件前面用過Nothing來解除這個引用或指標。

       對於.Net來說,儘管已經解除了所有引用有關聯,但並不是立即執行釋放,而是由垃圾回收機制來釋放,因此,

       無法預測準確的釋放物件的時間。

      釋放物件有幾種方法:

      一、Nothing

       二、賦予新的物件,以刪除對前面物件的引用。比如已經存在mPerson物件,然後用下面分配一個新的引用

                    mPerson=New Person     '這樣前面的引用就被解除了

               儘管沒顯式說明釋放前面的物件,但這個執行後,會自動刪除前面的引用。

               因為每個變數只能指向一個物件。改變指向後,前一個就失效了。

       三、走出作用域後,自動釋放。如下面,方法結束後,myPerson自動釋放。

    Private Sub DoSomething()
        Dim myPerson As Person
        myPerson = New Person
    End Sub

       四、程式結束時,所有變數、物件將銷燬。