演练:处理事件 (Visual Basic)
这是演示如何处理事件的两个主题中的第二个主题。 第一个主题演练:声明和引发事件演示了如何声明和引发事件。 本部分使用该演练中的窗体和类来演示如何在事件发生时对事件进行处理。
Widget
类示例使用传统的事件处理语句。 Visual Basic 提供了用于处理事件的其他技术。 作为练习,你可以将此示例修改成使用 AddHandler
和 Handles
语句。
处理 Widget 类的 PercentDone 事件
将以下代码放置在
Form1
中:Private WithEvents mWidget As Widget Private mblnCancel As Boolean
WithEvents
关键字指定变量mWidget
用于处理对象的事件。 通过提供要从中创建对象的类的名称来指定对象的类型。变量
mWidget
是在Form1
中声明的,因为WithEvents
变量必须是类级别。 无论你将它们放入哪种类类型中都是如此。变量
mblnCancel
用于取消LongTask
方法。
编写代码来处理事件
一旦使用 WithEvents
声明变量后,变量名称就会出现在类的“代码编辑器”的左侧下拉列表中。 选择 mWidget
时,Widget
类的事件将出现在右侧下拉列表中。 选择某一事件会显示相应的事件过程,带有前缀 mWidget
和下划线。 与 WithEvents
变量关联的所有事件过程都被赋予变量名称来作为前缀。
处理事件
从“代码编辑器”中的左侧下拉列表中选择
mWidget
。从右侧下拉列表中选择
PercentDone
事件。 “代码编辑器”将打开mWidget_PercentDone
事件过程。注意
可以使用“代码编辑器”来插入新的事件处理程序,但这不是必需的。 在本演练中,更直接的方法是只需将事件处理程序复制到代码中即可。
将以下代码添加到
mWidget_PercentDone
事件处理程序中:Private Sub mWidget_PercentDone( ByVal Percent As Single, ByRef Cancel As Boolean ) Handles mWidget.PercentDone lblPercentDone.Text = CInt(100 * Percent) & "%" My.Application.DoEvents() If mblnCancel Then Cancel = True End Sub
每当引发
PercentDone
事件时,事件过程会在Label
控件中显示完成百分比。DoEvents
方法允许重绘标签,同时还为用户提供单击“取消”按钮的机会。为
Button2_Click
事件处理程序添加以下代码:Private Sub Button2_Click( ByVal sender As Object, ByVal e As System.EventArgs ) Handles Button2.Click mblnCancel = True End Sub
如果在 LongTask
运行时用户单击“取消”按钮,在 DoEvents
语句允许进行事件处理后,会立即执行 Button2_Click
事件。 类级别的变量 mblnCancel
设置为 True
,mWidget_PercentDone
事件然后将对它进行测试并将 ByRef Cancel
参数设置为 True
。
将 WithEvents 变量连接到对象
Form1
现已设置为处理 Widget
对象的事件。 剩下的任务就是找到某处的 Widget
。
当在设计时声明变量 WithEvents
时,没有与它关联的对象。 WithEvents
变量与任何其他对象变量一样。 你需要创建一个对象,并使用 WithEvents
变量为它分配一个引用。
创建对象并为它分配引用
从“代码编辑器”中的左侧下拉列表中选择“(Form1 事件)”。
从右侧下拉列表中选择
Load
事件。 “代码编辑器”将打开Form1_Load
事件过程。为
Form1_Load
事件过程添加以下代码以创建Widget
:Private Sub Form1_Load( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles MyBase.Load mWidget = New Widget End Sub
此代码执行时,Visual Basic 将创建一个 Widget
对象,并将它的事件连接到与 mWidget
关联的事件过程。 从那一刻起,每当 Widget
引发它的 PercentDone
事件时,都将执行 mWidget_PercentDone
事件过程。
调用 LongTask 方法
将以下代码添加到
Button1_Click
事件处理程序中:Private Sub Button1_Click( ByVal sender As Object, ByVal e As System.EventArgs ) Handles Button1.Click mblnCancel = False lblPercentDone.Text = "0%" lblPercentDone.Refresh() mWidget.LongTask(12.2, 0.33) If Not mblnCancel Then lblPercentDone.Text = CStr(100) & "%" End Sub
在调用 LongTask
方法之前,必须初始化显示完成百分比的标签,并且用于取消方法的类级别的 Boolean
标志必须设置为 False
。
LongTask
调用的任务持续时间为 12.2 秒。 每三分之一秒引发一次 PercentDone
事件。 每次引发事件时,将执行 mWidget_PercentDone
事件过程。
LongTask
完成后,会对 mblnCancel
进行测试以查看 LongTask
是否正常结束,或者查看它是否由于 mblnCancel
设置为 True
而停止。 只有在前一种情况下才会更新完成百分比。
运行程序
按 F5 将项目置于运行模式。
单击“启动任务”按钮。 每次引发
PercentDone
事件时,都会使用完成的任务百分比来更新标签。单击“取消”按钮来停止任务。 请注意,当你单击“取消”按钮时,该按钮的外观不会立即更改。 只有在
My.Application.DoEvents
语句允许事件处理后,才能发生Click
事件。备注
My.Application.DoEvents
方法不会按照与窗体相同的方式来处理事件。 例如,在本演练中,必须单击“取消”按钮两次。 若要使窗体可以直接处理事件,你可以使用多线程处理。 有关详细信息,请参阅托管线程处理。
你可能会发现,通过 F11 运行程序并一次单步执行一行代码是具有指导意义的。 这样一来,你可以清楚地了解执行进入 LongTask
,并且随后在每次引发 PercentDone
事件时短暂重新进入 Form1
的方式。
如果在执行回到 Form1
的代码中时再次调用 LongTask
方法,会发生什么情况? 在最糟糕的情况下,如果每次引发事件时都调用 LongTask
,则可能会发生堆栈溢出。
你可以通过将对新 Widget
的引用分配给 mWidget
,使变量 mWidget
处理另一个不同 Widget
对象的事件。 事实上,每次单击 Button1_Click
按钮时,都可以使该按钮中的代码执行此操作。
处理不同小组件的事件
将以下代码行添加到
Button1_Click
过程中,紧靠在读取mWidget.LongTask(12.2, 0.33)
的行之前:mWidget = New Widget ' Create a new Widget object.
每次单击按钮时,上面的代码都会创建一个新的 Widget
。 LongTask
方法完成后,将释放对 Widget
的引用,并且将销毁 Widget
。
一个 WithEvents
变量一次只能包含一个对象引用,因此,如果你向 mWidget
分配不同的 Widget
对象,则不会再处理上一个 Widget
对象的事件。 如果 mWidget
是唯一包含对旧 Widget
引用的对象变量,则将销毁该对象。 如果要处理来自多个 Widget
对象的事件,请使用 AddHandler
语句单独处理每个对象中的事件。
注意
你可以根据需要声明多个 WithEvents
变量,但不支持 WithEvents
变量的数组。