VB.NET学习笔记:事件处理及自定义事件

测试环境:windows 7和Microsoft Visual Studio 2015

编程必然要知道事件,比如单击按钮事件,然后编写当事件发生时的处理代码,VB.NET是怎样进行事件处理的呢?可否自定义事件呢?因扩展控件,使其列头增加全选全不选复选框并具备分页功能需要用到自定义事件,详见博文《VB.NET学习笔记:WinForm自定义DataGridView分页组合控件》、《VB.NET学习笔记:自定义控件之扩展DataGridViewColumnHeaderCell类增加CheckBox全选复选框》,所以拜读了多篇相关事件的博文,结合自己在编程中的使用情况,谈谈我对事件的一些认识。
一、事件处理——把事件与处理事件的方法关联在一起
新建一个Windows窗体应用程序项目,在窗体里拉入一个Button控件,将其Name属性值修改为BtnEvent1,Text属性值修改为“按钮1”,然后双击按钮,即可自动生成如下按钮单击事件处理代码:

    Private Sub BtnEvent1_Click(sender As Object, e As EventArgs) Handles BtnEvent1.Click

    End Sub

当然也可以在代码窗口里,选择相应的项目名称,及其下相应的控件,就可以选择对应的事件,之后也会自动生成事件处理代码,如下图所示操作。
VB.NET学习笔记:事件处理及自定义事件_第1张图片
代码比VB6.0里的事件处理代码多了一些内容:
1、Handles BtnEvent1.Click:表明这个方法应处理BtnEvent1中的Click事件,Handles的目的就是把这个方法与Button类中的Click事件关联起来。
2、(sender As Object, e As EventArgs) :两个参数sender和e。这是控件类定义的参数,如果参数不对将引发错误。
参数sender和e到底是个啥呢?我们来测试一下,在事件处理代码中添加如下代码:

    Private Sub BtnEvent1_Click(sender As Object, e As EventArgs) Handles BtnEvent1.Click
        MessageBox.Show(sender.ToString)
        MessageBox.Show(e.ToString)
    End Sub

调试代码,测试结果如图所示:
VB.NET学习笔记:事件处理及自定义事件_第2张图片
VB.NET学习笔记:事件处理及自定义事件_第3张图片
经在csdn中查询得知:sender参数表示发送者,此处表示按钮。e参数是MouseEventArgs类,继承自EventArgs类,就是将鼠标的动作信息封装在这个类的对象e中。这个对象描述了鼠标点击情况,比如在按钮的那个位置点下了鼠标。我自己也不是很懂,在这里做个记号吧!
下面代码修改了事件处理的方法名:

Private Sub Btn1_Click(sender As Object, e As EventArgs) Handles BtnEvent1.Click
        MessageBox.Show(sender.ToString)
        MessageBox.Show(e.ToString)
    End Sub

BtnEvent1_Click修改成了Btn1_Click,如果在VB6.0是没有办法识别这个事件的,单击“按钮1”当然也不会执行此代码。但在vb.net中不影响事件的执行,说明在vb.net中,事件不再依赖方法名。
我们在窗体中再拉入一个Button控件,将其Name属性值修改为BtnEvent2,Text属性值修改为“按钮2”,然后添加如下按钮单击事件处理代码:

    Private Sub BtnEvent2_Click(sender As Object, e As EventArgs) Handles BtnEvent2.Click
        MessageBox.Show(sender.ToString)
        MessageBox.Show(e.ToString)
    End Sub

BtnEvent2_Click方法里代码与BtnEvent1_Click方法里的代码一模一样,参数也一样,只是关联的事件不同而已,我们可以这两个方法合成一个方法,然后关联到2个事件上:

    Private Sub BtnEvent1_Click(sender As Object, e As EventArgs) Handles BtnEvent1.Click, BtnEvent2.Click
        MessageBox.Show(sender.ToString)
        MessageBox.Show(e.ToString)
    End Sub

Handles关键字可以关联多个事件,用逗号隔开每个事件,每个事件都会导致方法执行。在合并方法时要求每个事件的参数个数及类型必须相同。
一个方法可以关联多个事件,当然一个事件也是可以引发多个方法。代码如下:

Private Sub BtnEvent1_Click1(sender As Object, e As EventArgs) Handles BtnEvent1.Click
        Me.Label1.Text = Me.Label1.Text & Environment.NewLine & "方法:BtnEvent1_Click1"
    End Sub

    Private Sub BtnEvent1_Click2(sender As Object, e As EventArgs) Handles BtnEvent1.Click
        Me.Label1.Text = Me.Label1.Text & Environment.NewLine & "方法:BtnEvent1_Click2"
    End Sub

    Private Sub BtnEvent1_Click3(sender As Object, e As EventArgs) Handles BtnEvent1.Click
        Me.Label1.Text = Me.Label1.Text & Environment.NewLine & "方法:BtnEvent1_Click3"
    End Sub

测试效果如下图所示:
VB.NET学习笔记:事件处理及自定义事件_第4张图片
可见,单击“按钮1”时,每个关联的方法都被执行了。
除了用Handles关键字关联事件与事件处理方法外,还可以用AddHandler关键字,请看下面代码:

    Private Sub BtnEvent1_Click(sender As Object, e As EventArgs) Handles BtnEvent1.Click
        RemoveHandler TextBox1.TextChanged, AddressOf TextBox1_TextChanged
        Me.TextBox1.Text = sender.ToString
        AddHandler TextBox1.TextChanged, AddressOf TextBox1_TextChanged
    End Sub

    Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
        MessageBox.Show("你修改了文本!")
    End Sub

不管是在窗体修改或是编程修改TextBox控件文本都会引发TextChanged事件,上面代码可以先暂停引发该事件,使用到RemoveHandler关键字来把事件跟处理事件的方法分离。

RemoveHandler TextBox1.TextChanged, AddressOf TextBox1_TextChanged

之后要记得用AddHandler关键字重新将事件TextBox1.TextChanged跟TextBox1_TextChanged方法关联,要不然就真的再不也会引发TextBox控件的TextChanged事件了。

AddHandler TextBox1.TextChanged, AddressOf TextBox1_TextChanged

学习小结:
(1)、把事件处理方法和事件关联的方式有两种:
A、Handles关键字:只要关联某方法后,就会一直关联。我们称其为静态方式。
B、AddHandler关键字:AddHandler可以在程序运行时动态的添加处理事件的方法,还可以用RemoveHanlder动态地删除处理事件的方法。
(2)、一个事件可以关联多个方法,一个方法也可以关联多个事件。
如果事件关联的方法不止一个时,引发事件就会执行全部关联的方法,我们无法干涉和终止,而且也不能预测执行方法的顺序。
二、自定义事件
在vb.net中事件可以看成为一种特殊的委托,也就是说可以将sub过程委托给事件,当触发事件时就会执行委托给该事件的sub。
1、使用自定义事件的步骤
(1)、声明事件
事件由委托实现,所以应事先声明一个事件的委托。

    Public Delegate Sub CustomEventHandler(ByVal str As String) '声明一个事件的委托
    Public Event CustomEvent As CustomEventHandler '声明一个自定义事件CustomEvent

也可以用简写,即上述声明等效于:

Public Event CustomEvent(ByVal str As String) '声明一个自定义事件CustomEvent

注意:声明事件可以带参数,但不能具有返回值、可选参数、ParamArray参数。也就是说不能将function函数委托给事件。
(2)、触发事件
使用RaiseEvent关键字来引发事件。
注意:触发事件时传入的参数必须与声明事件时的参数类型以及个数都要相同。

    Public Sub RaiseCustomEvent(ByVal str As String) '定义触发事件的方法
        RaiseEvent CustomEvent(str) '触发事件
    End Sub

(3)、编写处理事件的Sub方法
我这里编写的方法名为talk,带一个参数,特别注意的是传入方法的参数必须与声明事件时的参数类型以及个数都要相同。

Public Sub talk(ByVal str As String)
        Me.TextBox1.Text = str
    End Sub

(4)、把事件和处理事件的方法关联在一起
可以使用Handles关键字或AddHandler关键字,但使用Handles关键字一定要配合使用WithEvents关键字来声明事件所在的对象,如果不带WithEvents关键字不会报错,但若这个对象真的有事件,也不会引发;当然如果对象本身没有声明的事件,如果强行用WithEvents将会引发语法错误。所以WithEvents和Handles必须成对出现。
2、WithEvents和Handles关联事件方法
类代码:

Public Class ClsCustomEvent '自定义类
    'Public Delegate Sub CustomEventHandler(ByVal str As String) '声明一个事件的委托
    'Public Event CustomEvent As CustomEventHandler '声明一个自定义事件CustomEvent
    Public Event CustomEvent(ByVal str As String) '声明一个自定义事件CustomEvent
    Public Sub RaiseCustomEvent(ByVal str As String) '定义触发事件的方法
        RaiseEvent CustomEvent(str) '触发事件
    End Sub
End Class

窗体代码:

Public Class Form1
    Public WithEvents Custom As New ClsCustomEvent() '声明事件对象
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Custom.RaiseCustomEvent("Hello world") '执行ClsCustomEvent类中触发CustomEvent事件的方法
    End Sub

    Public Sub talk(ByVal str As String) Handles Custom.CustomEvent '将talk方法委托给ClsCustomEvent类的CustomEvent事件
        Me.TextBox1.Text = str
    End Sub
End Class

3、AddHandler关联事件方法
事件所在的类代码:

Public Class ClsCustomEvent '自定义类
    'Public Delegate Sub CustomEventHandler(ByVal str As String) '声明一个事件的委托
    'Public Event CustomEvent As CustomEventHandler '声明一个自定义事件CustomEvent
    Public Event CustomEvent(ByVal str As String) '声明一个自定义事件CustomEvent
    Public Sub RaiseCustomEvent(ByVal str As String) '定义触发事件的方法
        RaiseEvent CustomEvent(str) '触发事件
    End Sub
End Class

窗体代码:

Public Class Form1
    Public Custom As New ClsCustomEvent() '声明事件对象
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        AddHandler Custom.CustomEvent, AddressOf talk '将talk方法委托给ClsCustomEvent类的CustomEvent事件
        Custom.RaiseCustomEvent("Hello world") '执行ClsCustomEvent类中触发CustomEvent事件的方法
    End Sub

    Public Sub talk(ByVal str As String)
        Me.TextBox1.Text = str
    End Sub
End Class

注意: AddHandler与RemoveHandler最好能成对出现,如果不将事件处理程序与事件分离(RemoveHanlder),对象将保留在内存中,即使上面Custom不再指向对象,每个事件仍有对象的一个引用,容易出现内存泄露。而WithEvents会自动处理这些细节。

本文借鉴与参考了以下博文:
VB.net学习笔记(七)对象事件的定制
vb.net中的委托与事件
学习过程得到网友uruseibest的帮助,表示感谢!

你可能感兴趣的:(VB.NET学习笔记:事件处理及自定义事件)