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来声明。这就是定制事件。

委托,生活中常见的委托人,委托某人办某事,就是此意。

委托,委托,就是你办不了事情,委托别人去办... 对计算机来说,计算机线程外的东西,是没办法直接被线程调用

为了能让线程执行调用不到的事件,那就建立委托吧
委托就产生了
先定义一个委托体:DelegateSubSetTxtOutputCallback(ByValksksAsstring)
委托了,就不会冲突了

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

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,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
四、程序结束时,所有变量、对象将销毁。

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...