分享

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

 百眼通 2014-10-31


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

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


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

VB.net中,可用Net委托机制提供事件支持。





1、事件处理

  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,这无关痛痒,可以是其它名,例如:

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

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

       所以更改方法名,只要后面的参数及Handles正确,一样正常。





2、处理多个事件

      Handles关键字提供了灵活的关联,它可以关联多个事件,这多个事件可用逗号隔开,每个事件都会导致方法运行。

  1. 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)
         委托了,就不会冲突了

        下面是各部分的代码,先定义一个事件的委托,然后定义一个变量用来跟踪侦听的变量,然后定制事件存储与触发(结构)

  1. Public Delegate Sub WalkedEventHandler(ByVal distance As Int32)  
  2.   
  3. Private mWalkedHandlers As WalkedEventHandler  
  4.   
  5. Public Custom Event Walked As WalkedEventHandler  
  6.   
  7.     AddHandler(ByVal value As WalkedEventHandler)  
  8.         mWalkedhandlers = CType([delegate].combine(mWalkedhandlers, value), _WalkedEventHandler)  
  9.     End AddHandler  
  10.   
  11.     RemoveHandler(ByVal value As WalkedEventHandler)  
  12.         mwalkedhandlers = CType([delegate].remove(mWalkedHandlers, value), WalkedEventHandler)  
  13.     End RemoveHandler  
  14.   
  15.     RaiseEvent(ByVal distance As Integer)  
  16.         If mWalkedHandlers isnot Nothing thdn  
  17.             mWalkedHandlers.invoke(distance)  
  18.         End If  
  19.     End RaiseEvent  
  20.   
  21. End Event  

          上面AddHandler用于添加一个新处理程序。

                  RemoveHandler用于停止接收事件的某个事件处理程序

                  RaiseEvent 触发调用事件。


  




6、WithEvents

      它声明要接收该对象引发的任何事件。如果没有用WithEvents不会出错,但不会接收该对象中的事件。

      当我们引发事件RaiseEvent时,可能误认为是由多线程来完成的,其实不然,这个过程只是一个线程,
      引发事件类似调用方法,正如调用函数一样,返回后再继续向下执行。
      下面执行的顺序是:1234567








7、动态的增加接收事件和取消事件

     前面的WithEvents和Handles就象难兄弟一样,成对出现,而且他们是死结,一旦出现无法取消,就象死咒一样。

 

     为了适应灵活的情况,可以不用上面,而使用另一对灵动的兄弟AddHanlder和RemoveHanlder。

      AddHanlder可以动态地添加事件处理程序,RemoveHanlder可以动态地删除事件处理程序。

       因为这种链接是在运行时建立的,能够更多地控制过程(比如加入判断,达到要求就可建立链接,否则没有链接)

  1. Public Class Form1  
  2.   
  3.     Private mobjPerson As Person  
  4.   
  5.     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load  
  6.         mobjPerson = New Person()  
  7.         AddHandler mobjPerson.Walked, AddressOf OnWalk '动态加入事件(作用与withEvents与Handles链接类似)  
  8.     End Sub  
  9.   
  10.     Private Sub OnWalk(ByVal Distance As Integer)  
  11.         MessageBox.Show("Person walked " & Distance)  
  12.     End Sub  
  13.   
  14.     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click  
  15.         mobjPerson.Walk(42)  
  16.     End Sub  
  17.   
  18. End Class  
  19.   
  20.   
  21. Public Class Person  
  22.     Private mintTotalDistance As Integer  
  23.     Public Event Walked(ByVal Distance As Integer)  
  24.   
  25.     Public Sub Walk(ByVal Distance As Integer)  
  26.         mintTotalDistance += Distance  
  27.         RaiseEvent Walked(Distance)  
  28.     End Sub  
  29.   
  30. End Class  

           注意:如果不将事件处理程序与事件分离(RemoveHanlder),对象将保留在内存中,即使上面mobjPerson不再指向对象,每个事件仍有对象的一个引用。

                       所以AddHandler与RemoveHandler必须成对出现,不然易出现内存泄露。而WithEvents会自动处理这些细节。

              下面是不同情况加入不同的链接:

  1. Public Class Form1  
  2.   
  3.     Private mobjPerson As Person  
  4.   
  5.     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load  
  6.         mobjPerson = New Person()  
  7.         If Microsoft.VisualBasic.Command = "nodisplay" Then '检测IDE中命令行是否为nodiaplay  
  8.             AddHandler mobjPerson.Walked, AddressOf LongOnWalk '关联一个事件  
  9.         Else  
  10.             AddHandler mobjPerson.Walked, AddressOf OnWalk     '关联另一个事件  
  11.         End If  
  12.     End Sub  
  13.   
  14.     Private Sub OnWalk(ByVal Distance As Integer)  
  15.         MessageBox.Show("Person walked " & Distance)  
  16.     End Sub  
  17.   
  18.     Private Sub LongOnWalk(ByVal Distance As Integer)  
  19.         System.Diagnostics.Debug.WriteLine("Person walked" & Distance)  
  20.     End Sub  
  21.   
  22.     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click  
  23.         mobjPerson.Walk(42)  
  24.     End Sub  
  25.   
  26. End Class  
  27.   
  28.   
  29. Public Class Person  
  30.     Private mintTotalDistance As Integer  
  31.     Public Event Walked(ByVal Distance As Integer)  
  32.   
  33.     Public Sub Walk(ByVal Distance As Integer)  
  34.         mintTotalDistance += Distance  
  35.         RaiseEvent Walked(Distance)  
  36.     End Sub  
  37.   
  38. End Class  

           同样,分离这种关系时,也应对应着分离:

  1. If Microsoft.VisualBasic.Command = "nodisplay" Then  
  2.     RemoveHandler mobjPerson.Walked, AddressOf LongOnWalk  
  3. Else  
  4.     RemoveHandler mobjPerson.Walked, AddressOf OnWalk  
  5. End If  
  6. mobjPerson = New Person  






8、构造函数

      这个C++老讲,不再说了。

      VB.net用New做构造函数,在对象产生时进行初始化,对每个对象它只运行一次。

      不带参数的New:

  1. Public Sub New()  
  2.   Phone("home") = "555-1234"  
  3.   Phone("work") = "555-5678"  
  4. End Sub  


        带参数的New:

  1. Public Sub New(ByVal Name As String, ByVal BirthDate As Date)  
  2.   mstrName = Name  
  3.   mdtBirthDate = BirthDate  
  4.   Phone("home") = "555-1234"  
  5.   Phone("work") = "555-5678"  
  6. End Sub  


       类中可以有几个New构造函数,它们可以重载。当使用时智能会提示有几个New函数,如下面提示有2个










9、释放对象

       释放对象前面用过Nothing来解除这个引用或指针。


       对于.Net来说,尽管已经解除了所有引用有关联,但并不是立即执行释放,而是由垃圾回收机制来释放,因此,

       无法预测准确的释放对象的时间。


      释放对象有几种方法:

      一、Nothing

       二、赋予新的对象,以删除对前面对象的引用。比如已经存在mPerson对象,然后用下面分配一个新的引用

                    mPerson=New Person     '这样前面的引用就被解除了

               尽管没显式说明释放前面的对象,但这个执行后,会自动删除前面的引用。

               因为每个变量只能指向一个对象。改变指向后,前一个就失效了。

       三、走出作用域后,自动释放。如下面,方法结束后,myPerson自动释放。

  1. Private Sub DoSomething()  
  2.     Dim myPerson As Person  
  3.     myPerson = New Person  
  4. End Sub  

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



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多