VBA:在用户窗体上使用WithEvents

22

我有一个包含60多个不同类型控件的Word用户窗体。 我想在每次触发control_change事件时评估该表单,并更改表单提交按钮的启用状态。然而,我真的不想编写和维护60个onchange事件处理程序。

2个回答

33

你可以创建一个事件接收器类,该类将包含特定类型的所有控件的事件处理代码。

例如,创建名为TextBoxEventHandler的类,如下所示:

Private WithEvents m_oTextBox as MSForms.TextBox

Public Property Set TextBox(ByVal oTextBox as MSForms.TextBox)
    Set m_oTextBox = oTextBox
End Property

Private Sub m_oTextBox_Change()
    ' Do something
End Sub

现在你需要为表单上每个适当类型的控件创建并连接该类的一个实例:

Private m_oCollectionOfEventHandlers As Collection

Private Sub UserForm_Initialise()

    Set m_oCollectionOfEventHandlers = New Collection

    Dim oControl As Control
    For Each oControl In Me.Controls

        If TypeName(oControl) = "TextBox" Then

            Dim oEventHandler As TextBoxEventHandler
            Set oEventHandler = New TextBoxEventHandler

            Set oEventHandler.TextBox = oControl

            m_oCollectionOfEventHandlers.Add oEventHandler

        End If

    Next oControl

End Sub

请注意,你需要将事件处理程序实例添加到集合中的原因仅是确保它们保持引用状态,因此在使用完它们之前不会被垃圾收集器丢弃。

显然,这种技术可以扩展到处理其他类型的控件。您可以为每种类型单独创建事件处理程序类,也可以使用一个具有成员变量(以及相关属性和事件处理程序)的单个类来处理所需处理的每种控件类型。


@Alex:不行,因为每个控件都需要一个类的实例。否则,事件处理程序将不知道事件是针对哪个控件的。如果只有事件处理程序有像C#事件处理程序一样的“sender”参数就好了... - Gary McGill
1
@Zac:是的,它应该完全以相同的方式工作。只需将代码“放入”工作表模块(默认命名为Sheet1等),并使用适当的Sheet_xxx事件即可。如果您要处理的工作表数量较少且固定,则可以这样做;如果您需要处理由用户创建的工作表(对于这种情况,您可能需要使用插件)。 - Gary McGill
3
这段代码适用于文本框,当尝试将其应用于复选框时,需要将“CheckBox”指定为“MSForms.CheckBox”。这些信息可能对某些人很有用。 - Marcel
我在运行时编译Private WithEvents m_oTextBox As TextBox时遇到了“对象不会引发自动化事件”的错误。有人有什么想法吗?- 我知道4/12年前的事情现在已经很久了...(使用Office 2016) - casewolf
啊,需要更改为:Private WithEvents m_oTextBox As MSForms.TextBox,然后它就可以编译了。 - casewolf
显示剩余2条评论

2

在这种情况下,你的选择很少,因为在VBA/VB6中无法共享事件处理程序。

选项1:使用一个中央处理函数,该函数从每个事件处理程序中调用。

Sub Control1_ChangeEvent()
  CommonChangeEvent // Just call the common handler, parameters as needed
End Sub

Sub Control2_ChangeEvent()
  CommonChangeEvent
End Sub
...
Sub CommonChangeEvent(/* Add necessary parameters */)
  //Do the heavy lifting here
End Sub

选项2:将您的控件组织成控件数组。

Sub TextBox_ChangeEvent(Index As Integer)
  CommonChangeEvent
End Sub

Sub OtherControlType_ChangeEvent(Index As Integer)
  CommonChangeEvent
End Sub

将这两个选项结合起来,您的总事件处理程序数量将大大缩小,剩余的处理程序只是一个真正事件处理程序的无脑桩。


7
在这种情况下,选项2不可行。VBA不支持控件数组。 - Gary McGill
1
@GaryMcGill:这条评论来得有点晚了,但是对于控件数组,你可能想看看http://www.siddharthrout.com/index.php/2018/01/15/vba-control-arrays/。 - Siddharth Rout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接