我正在使用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
我收到以下错误:“程序声明与该行上具有相同名称的事件或程序的描述不匹配。
任何想法我做错了什么?
答案 0 :(得分:1)
事件处理程序具有特定签名,由特定接口拥有:您无法更改签名,否则该成员将不匹配接口定义的签名,并且无法编译 - 正如您所观察到的那样。
为什么?
假设您有一个CommandButton
类,它处理本机Win32消息并调度它们 - 可能看起来像这样:
Public Event Click()
Private Sub HandleNativeWin32Click()
RaiseEvent Click
End Sub
现在代码中的其他地方,您希望使用该类并处理其Click
事件:
Private WithEvents MyButton As CommandButton
Private Sub MyButton_Click()
'button was clicked
End Sub
请注意,处理程序方法名为[EventSource]_[EventName]
- 这是VBA中的硬连接,您无法更改它。如果您尝试与名称中包含下划线的公共成员建立接口,则会遇到问题。这就是为什么一切都是PascalCase
(没有下划线),无论你在标准库中的哪个位置。
因此,编译器知道您正在处理MyButton.Click
事件,因为有一个名为MyButton_Click
的方法。然后它查看参数 - 如果存在不匹配,则表示存在错误:该参数不在接口上,那么事件提供程序将如何提供该参数?。因此它会抛出编译时错误,告诉您需要进行签名匹配,或重命名该过程,使其看起来不再处理MyButton.Click
。
当您将控件放到表单上时,您基本上可以免费获得Public WithEvents Button1 As CommandButton
模块级变量:这就是您在代码中使用Button1
来引用该特定按钮的方式,以及它的Click
处理程序如何命名为Button1_Click
。请注意,如果重命名按钮但不重命名处理程序,则该过程将不再处理按钮的Click
事件。您可以在表单设计器上使用Rubberduck的重构/重命名工具,在不破坏代码的情况下正确重命名控件。
VBA中的变量可以位于以下三个范围之一:全局,模块或过程级别。
当你这样做时:
Sub DoSomething()
Dim foo
End Sub
您正在声明本地范围变量。
每个模块顶部都有一个声明部分,您可以在其中声明模块范围变量(以及其他内容)。
Option Explicit
Private foo
Sub DoSomething()
End Sub
此处foo
是模块范围变量:该模块中的每个过程都可以访问它 - 读取和写入。
因此,如果您希望在程序之间传递数据并且无法更改其签名,那么您的下一个最佳选择是声明模块范围变量。
[故意忽略全球范围]
关于As New
- 请考虑一下:
Public Sub Test()
Dim foo As Collection
Set foo = 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 New Collection
Set foo = Nothing
foo.Add 42
Debug.Print foo.Count
End Sub
此代码输出1,因为As New
以一种奇怪的,不直观且令人困惑的方式使对象保持活着状态。在可能的情况下尽量避免使用As New
。
答案 1 :(得分:0)
在模块级别声明字典并将其填入button-1-click事件处理程序。然后可以在按钮2单击事件处理程序中简单地重复使用它。因此,不需要将字典传递给事件处理程序,这也是不可能的。 HTH
表单模块
Option Explicit
' Declare dictionary at the user form module level
Private ISINDict As Scripting.Dictionary
Private Sub CommandButton1_Click()
FillDictionary
End Sub
Private Sub CommandButton2_Click()
' Use the dictionary filled in event handler of CommandButton-1
End Sub
Private Sub FillDictionary()
With ISINDict
.Add "Key-1", "Itm-1"
.Add "Key-2", "Itm-2"
.Add "Key-3", "Itm-3"
End With
End Sub
Private Sub UserForm_Initialize()
Set ISINDict = New Scripting.Dictionary
End Sub