vba - 是否可以在自定义用户窗体中创建和处理自定义事件?

标签 vba excel

我有一个 UserForm我在其中添加了一个具有足够 Let 和 Get 语句的属性。我希望在属性更改时触发事件。事件,RaiseEvent和例程已经说明,都在UserForm模块。但是,我找不到将例程分配给事件的方法。

据我所知,这与类模块情况下通常的自定义事件不同,因为它没有在类模块中声明,我可以在常规模块中实例化其类。我所有的搜索都提供了类模块中的自定义事件或用户窗体中的内置事件的示例,但没有关于用户窗体中的自定义事件的 Material 。

这实际上让我想知道是否有可能在 UserForms 和 Private Subs 中创建自定义事件来处理这些事件。那么有可能做到吗?如果是这样,我错过了什么?如何制作 Private Sub UFStatus_StatusChange()处理事件?

任何帮助将不胜感激!

到目前为止,代码都在 UserForm 模块中:

Public Event StatusChange (old_status As Long, current_status As Long)

Dim old_status As Long

Private current_status As Long

Public Property Let UFStatus (RHS As Long)
    old_status = current_status
    current_status = RHS
    RaiseEvent StatusChange(old_status, current_status)

End Property

Private Sub UFStatus_StatusChange()
    MsgBox("Status changed from " & old_status & "to " & current_status)
End Sub

最佳答案

是的,但您需要先了解 VBA/COM 事件的工作原理。

一点背景...

注意到 VBE 代码 Pane 顶部的下拉菜单/组合框了吗?最左边的是列出所有可用的接口(interface)和事件提供者 - 最右边的是列出可用的成员和事件,这些成员和事件由最左边的下拉列表中选择的任何内容公开。

所以当你处理 Click一些事件OkButtonUserForm1 的代码隐藏中,处理程序 stub 可能如下所示:

Private Sub OkButton_Click()

End Sub

签名以非常特殊的方式构造,始终以相同的方式构造,无论您是实现接口(interface)还是处理事件:
Private Sub [Provider]_[MemberName]([Args])

这强调了问题。无论你做什么,不要使用包含下划线的标识符命名事件(或接口(interface)成员)。如果发生事件,您将遇到编译错误:

Compile error: Invalid event name



对于接口(interface),您还会收到编译错误,VBE 会提示接口(interface)成员未实现。

这就是为什么一切都是PascalCase而不是 Upper_Snake_Case在 VB 中。遵守约定,避免在公共(public)成员名称中使用下划线。

如果您不确定接口(interface)是什么以及为什么我在有关事件的帖子中提到它们,请查找 Implements关键字,知道接口(interface)和事件密切相关并且以非常相似的方式工作,并继续阅读;-)

提供者

任何类都可以定义事件。一个 UserForm作为一个类,它绝对可以定义事件,是的。您可以使用 Event 准确定义事件。关键词:
Public Event SomethingHappened(ByVal SomeArg As Long)

定义事件的类是事件提供者——它是唯一允许引发它定义的事件的类。

您使用 RaiseEvent 引发事件关键字,并提供参数:
Private Sub OnSomethingHappened()
    RaiseEvent SomethingHappened(42)
End Sub

您何时以及为何提出事件完全取决于您的想象。

客户端

考虑 Click CommandButton 的事件在 UserForm : CommandButton类可能有一个方法来监听涉及鼠标的 Win32 消息,当它决定处理左键单击时,它会引发它的 Click事件,和一些东西和噗的OkButton_Click程序运行。正确的?

MSForms 自动为您做的部分是,当您添加 CommandButton在表格上,并将其命名为 OkButton ,好吧这个OkButton identifier 本质上成为表单上的公共(public)字段,就好像您添加了一个公共(public)的模块级变量一样:
Public OkButton As MSForms.CommandButton

除了,它实际上看起来像这样:
Public WithEvents OkButton As MSForms.CommandButton

WithEvents关键字使 OkButton在左侧下拉列表中可用 - OkButton成为事件提供者,其Click事件可以被处理......在表单的代码隐藏中。
CommandButton类不知道也不关心它的 Click 的处理程序事件:事件提供者是OkButton对象,客户端是 UserForm1你在其中实现处理程序的类。

换句话说,事件提供者和客户端是两个完全独立的类。

问题是 WithEvents仅在类模块中是合法的。

你可以让你的UserForm1事件提供者,但它不能处理自己的事件。

在您的 UserForm1 中声明事件代码隐藏,并确保指定 ByVal parameters 用于在处理程序站点上只读的参数 - 使用 ByRef当处理程序可以修改值时,例如对于一些 Cancel As Boolean处理程序返回时可以读取的参数:
Public Event StatusChange(ByVal oldStatus As Long, ByVal newStatus As Long)

现在添加一个类模块,命名为MyPresenter :
Option Explicit
Private WithEvents MyView As UserForm1

Private Sub Class_Initialize()
    Set MyView = New UserForm1
End Sub

Private Sub Class_Terminate()
    Set MyView = Nothing
End Sub

Public Sub ShowDialog()
    MyView.Show
End Sub

选择 MyView从最左边的下拉列表中;最右边的下拉菜单应包含 StatusChange事件 - 并选择它应该创建一个处理程序 stub :
Private Sub MyView_StatusChange(ByVal oldStatus As Long, ByVal newStatus As Long)
    MsgBox "Status changed from " & oldStatus & " to " & newStatus & "!"
End Sub

现在,在您通常显示表单的标准/程序模块中,实例化该演示者类:
Public Sub Macro1()
    With New MyPresenter
        .ShowDialog
    End With
End Sub

关于vba - 是否可以在自定义用户窗体中创建和处理自定义事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49660399/

相关文章:

ms-access - 提供起始位置时 InStrRev 的行为不稳定

excel - VBA 单元格复制字符限制

vba - .将图片添加到Word文档: Invalid Property Assignment

c# - 如何将数据写入excel文件并在asp.net中下载

mysql - 使用设备开/关状态更改创建时间线

r - 使用 openxlsx 按单元格填充颜色过滤 Excel 中突出显示的数据

excel - 打开两个不同的工作簿时出现运行时错误 1004

vba - 在调用 .add() 之前添加项目的字典对象

excel - 不同工作表上具有范围标准的 COUNTIFS

excel - 当 CSS 按钮元素没有任何 ID 时,如何使用 VBA Selenium 正确定位 CSS 按钮元素?