对象还有一个重要的特性:事件
根据需要调用指定的功能,与对象交互作用。即:在运行过程中某动作发生后,给对象提供通知。
对象引发自己的事件,通过这个机制通知客户端代码执行了重要的操作或事件。
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来声明。这就是定制事件。
委托,生活中常见的委托人,委托某人办某事,就是此意。
委托,委托,就是你办不了事情,委托别人去办... 对计算机来说,计算机线程外的东西,是没办法直接被线程调用的
委托就产生了
下面是各部分的代码,先定义一个事件的委托,然后定义一个变量用来跟踪侦听的变量,然后定制事件存储与触发(结构)
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不会出错,但不会接收该对象中的事件。
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四、程序结束时,所有变量、对象将销毁。