演练:处理事件 (Visual Basic)

这是演示如何处理事件的两个主题中的第二个主题。 第一个主题演练:声明和引发事件演示了如何声明和引发事件。 本部分使用该演练中的窗体和类来演示如何在事件发生时对事件进行处理。

Widget 类示例使用传统的事件处理语句。 Visual Basic 提供了用于处理事件的其他技术。 作为练习,你可以将此示例修改成使用 AddHandlerHandles 语句。

处理 Widget 类的 PercentDone 事件

  1. 将以下代码放置在 Form1 中:

    Private WithEvents mWidget As Widget
    Private mblnCancel As Boolean
    

    WithEvents 关键字指定变量 mWidget 用于处理对象的事件。 通过提供要从中创建对象的类的名称来指定对象的类型。

    变量 mWidget 是在 Form1 中声明的,因为 WithEvents 变量必须是类级别。 无论你将它们放入哪种类类型中都是如此。

    变量 mblnCancel 用于取消 LongTask 方法。

编写代码来处理事件

一旦使用 WithEvents 声明变量后,变量名称就会出现在类的“代码编辑器”的左侧下拉列表中。 选择 mWidget 时,Widget 类的事件将出现在右侧下拉列表中。 选择某一事件会显示相应的事件过程,带有前缀 mWidget 和下划线。 与 WithEvents 变量关联的所有事件过程都被赋予变量名称来作为前缀。

处理事件

  1. 从“代码编辑器”中的左侧下拉列表中选择 mWidget

  2. 从右侧下拉列表中选择 PercentDone 事件。 “代码编辑器”将打开 mWidget_PercentDone 事件过程。

    注意

    可以使用“代码编辑器”来插入新的事件处理程序,但这不是必需的。 在本演练中,更直接的方法是只需将事件处理程序复制到代码中即可。

  3. 将以下代码添加到 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 方法允许重绘标签,同时还为用户提供单击“取消”按钮的机会。

  4. 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 设置为 TruemWidget_PercentDone 事件然后将对它进行测试并将 ByRef Cancel 参数设置为 True

将 WithEvents 变量连接到对象

Form1 现已设置为处理 Widget 对象的事件。 剩下的任务就是找到某处的 Widget

当在设计时声明变量 WithEvents 时,没有与它关联的对象。 WithEvents 变量与任何其他对象变量一样。 你需要创建一个对象,并使用 WithEvents 变量为它分配一个引用。

创建对象并为它分配引用

  1. 从“代码编辑器”中的左侧下拉列表中选择“(Form1 事件)”。

  2. 从右侧下拉列表中选择 Load 事件。 “代码编辑器”将打开 Form1_Load 事件过程。

  3. 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 而停止。 只有在前一种情况下才会更新完成百分比。

运行程序

  1. 按 F5 将项目置于运行模式。

  2. 单击“启动任务”按钮。 每次引发 PercentDone 事件时,都会使用完成的任务百分比来更新标签。

  3. 单击“取消”按钮来停止任务。 请注意,当你单击“取消”按钮时,该按钮的外观不会立即更改。 只有在 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.
    

每次单击按钮时,上面的代码都会创建一个新的 WidgetLongTask 方法完成后,将释放对 Widget 的引用,并且将销毁 Widget

一个 WithEvents 变量一次只能包含一个对象引用,因此,如果你向 mWidget 分配不同的 Widget 对象,则不会再处理上一个 Widget 对象的事件。 如果 mWidget 是唯一包含对旧 Widget 引用的对象变量,则将销毁该对象。 如果要处理来自多个 Widget 对象的事件,请使用 AddHandler 语句单独处理每个对象中的事件。

注意

你可以根据需要声明多个 WithEvents 变量,但不支持 WithEvents 变量的数组。

另请参阅