VB.net学习笔记(七)对象事件的定制

来源:互联网 发布:dnf端口团队网盘 编辑:程序博客网 时间:2024/05/16 07:13


对象还有一个重要的特性:事件

根据需要调用指定的功能,与对象交互作用。即:在运行过程中某动作发生后,给对象提供通知。


对象引发自己的事件,通过这个机制通知客户端代码执行了重要的操作或事件。

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 WalkedEventHandlerPublic 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 RaiseEventEnd 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 SubEnd ClassPublic 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 SubEnd 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 SubEnd ClassPublic 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 SubEnd 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

       四、程序结束时,所有变量、对象将销毁。



原创粉丝点击