Vba 将参数传递给事件处理程序过程

Vba 将参数传递给事件处理程序过程,vba,excel,Vba,Excel,我正在使用userform上的一个按钮生成脚本字典,使用它填充列表框,然后需要使用表单上的第二个按钮使用同一个字典。我已声明我的词典使用早期绑定,如下所示: Dim ISINDict As New Scripting.Dictionary 还是迟订 Dim ISINDict as Object ... Set ISINDict = CreateObject("Scripting.Dictionary") 当我尝试将字典传递到另一个按钮时,如下所示: Private Sub OKButton_

我正在使用userform上的一个按钮生成脚本字典,使用它填充列表框,然后需要使用表单上的第二个按钮使用同一个字典。我已声明我的词典使用早期绑定,如下所示:

Dim ISINDict As New Scripting.Dictionary
还是迟订

Dim ISINDict as Object
...
Set ISINDict = CreateObject("Scripting.Dictionary")
当我尝试将字典传递到另一个按钮时,如下所示:

Private Sub OKButton_Click(ISINDict as Scripting.Dictionary) 'if early binding
Private Sub OKButton_Click(ISINDict as Object) 'if late binding
我得到以下错误:“过程声明与该行中事件或同名过程的描述不匹配”


知道我做错了什么吗?

事件处理程序有一个特定的签名,由特定接口拥有:您不能更改签名,否则成员将与接口定义的签名不匹配,并且无法编译—正如您所观察到的

为什么呢

假设您有一个
CommandButton
类,该类处理本机Win32消息并对其进行分派-可能如下所示:

Public Event Click()

Private Sub HandleNativeWin32Click()
    RaiseEvent Click
End Sub
现在,在代码的其他地方,您希望使用该类并处理其
单击
事件:

Private WithEvents MyButton As CommandButton

Private Sub MyButton_Click()
    'button was clicked
End Sub
请注意,处理程序方法的名称为
[EventSource].[EventName]
——这在VBA中是硬连接的,您无法更改它。如果您试图与名称中带有下划线的公共成员建立接口,您将遇到问题。这就是为什么无论您在标准库中的哪个位置查看,所有内容都是
PascalCase
(没有下划线)

因此编译器知道您正在处理
MyButton.Click
事件,因为有一个名为
MyButton\u Click
的方法。然后查看参数-如果存在不匹配,则说明有问题:该参数不在接口上,那么事件提供程序将如何提供该参数?。因此,它会抛出一个编译时错误,告诉您需要使签名匹配,或者重命名过程,使其看起来不像是在处理
MyButton。再单击

当你把一个控件放到一个窗体上时,你基本上得到了一个
Public with events Button1作为CommandButton
模块级变量,这是免费的:这就是你可以在代码中使用
Button1
来引用那个特定按钮的方式,以及它的
Click
处理程序是如何命名的
Button1\u Click
。请注意,如果重命名按钮而不是处理程序,则过程将不再处理按钮的
单击事件。您可以在表单设计器上使用的重构/重命名工具在不破坏代码的情况下正确重命名控件


VBA中的变量可以位于三个范围之一:全局、模块或过程级别

当您这样做时:

Sub DoSomething()
    Dim foo
End Sub
您正在声明一个局部范围变量

每个模块的顶部都有一个声明部分,您可以在其中声明模块范围变量(以及其他内容)

这里的
foo
是一个模块范围变量:该模块中的每个过程都可以访问它-读和写

因此,如果您有要在过程之间传递的数据,并且无法更改它们的签名,那么下一个最佳选择就是声明一个模块范围变量

[故意忽略全局范围]


关于<代码>作为新的< /代码> -考虑这一点:

Public Sub Test()
    Dim foo As Collection
    Set foo = New Collection
    Set foo = Nothing
    foo.Add 42
    Debug.Print foo.Count
End Sub
Public Sub Test()
    Dim foo As New Collection
    Set foo = Nothing
    foo.Add 42
    Debug.Print foo.Count
End Sub
此代码出现运行时错误91“未设置对象变量”,因为当执行
foo.Add
时,
foo
的引用是
Nothing
,这意味着没有有效的对象指针。现在考虑这个问题:

Public Sub Test()
    Dim foo As Collection
    Set foo = New Collection
    Set foo = Nothing
    foo.Add 42
    Debug.Print foo.Count
End Sub
Public Sub Test()
    Dim foo As New Collection
    Set foo = Nothing
    foo.Add 42
    Debug.Print foo.Count
End Sub

此代码输出1,因为
作为新的
以一种奇怪、不直观和混乱的方式保持对象的活动状态。尽可能避免将
作为新的

在模块级别声明字典,并将其填入button-1-click事件处理程序。然后,它可以简单地在button-2-click事件处理程序中重复使用。因此,不需要将字典传递给事件处理程序,这也是不可能的。嗯

表单模块


不能将参数添加到
单击事件中。您需要找到其他方法来执行您正在尝试执行的操作,例如将字典声明为表单级变量,然后您可以从
单击
事件中访问它。^他说的。还有,究竟为什么要延迟绑定脚本运行时??您的任何用户是否正在运行IE5.5或Windows XP?FWIW您不应该将局部变量
声明为新的
Dim foo作为新集合
/
Set foo=Nothing
/
Debug.Print foo.Count
->您希望得到什么?运行时错误91?如果是这样的话,你已经被新的
的非直觉行为咬了一口。谢谢大家!我会考虑这一点@braX如何将字典声明为表单级变量?这似乎是最好的选择!@Mat的杯子我这样做只是为了测试它,因为我在早期绑定时遇到了错误,我想确保它不相关-我对VBA非常陌生,所以如果不可能的话,请原谅我的无知!你的第二句话把我弄糊涂了。你能详细说明一下吗?在所有子程序之外对其进行尺寸标注。