为什么我不能从这个集合的成员获得属性?

时间:2010-04-30 11:10:50

标签: vba excel-vba collections excel

我已经为集合添加了一些表单控件,并且当我通过索引引用成员时可以检索它们的属性。

但是,当我尝试通过引用集合的成员来使用任何属性时,我看到'无法设置ControlSource属性。在“本地”窗口中找不到“”成员。

以下是代码的简化版本:

'Add controls to collection'
For x = 0 To UBound(tabs)
    activeTabs.Add Item:=Form.MultiPage.Pages(Val(tabs(x, 1))), _
        key:=Form.MultiPage.Pages(Val(tabs(x, 1))).Caption
Next x

'Check name using collection index'
For x = 0 To UBound(tabs)
    Debug.Print "Tab name from index: " & activeTabs(x + 1).Caption
Next x

'Check name using collection members'
For Each formTab In activeTabs
    Debug.Print "Tab name from collection: " & formTab.Caption
Next formTab

立即窗口中的结果是:

Tab name from index: Caption1
Tab name from index: Caption2
Tab name from collection: 
Tab name from collection: 

为什么一种方法有效,另一种方法失败?

这是一个标准的代码模块,但我有类似的代码在表单模块中工作得很好。这可能与它有关吗?

已编辑添加

formTab被声明为一个Control,但我发现如果它被声明为一个Object,那么代码就可以了。

这可能会解决我的问题,但为了进一步了解我的知识,我将非常感谢对此行为的任何解释,特别是关于在不同类型的模块中运行代码的差异。

1 个答案:

答案 0 :(得分:4)

这是一个非常好的问题。您在帖子末尾的编辑揭示了很多关于VBA如何工作以及这里发生了什么的信息。我不是100%这是正在发生的事情,但我会解释我的想法。

VBA中的Collection(和VB6一样;相同的代码库)不是强类型的。这意味着集合中的所有内容在技术上都是“对象”。在.NET世界中(从.NET 2.0开始),可以使用强类型集合,以便您可以说“此集合中的所有内容都是Control对象”。在VBA中,使用Collection无法实现此目的。

在第一次迭代中,您指的是activeTabs集合中索引的项目,activeTabs(x + 1)指的是object。当你告诉VBA查找该对象的.Caption时,它不知道底层类型是什么(我认为),所以它必须只是查看底层对象类型是否包含一个被调用的属性或方法Caption。如您所见,Tab控件实际上包含一个名为Caption的属性。

在你进行For Each循环的第二次交互中,我认为问题是Control类型可能没有名为Caption的属性,尽管不同< em> types 控件可能会这样做。例如,文本框控件可能没有Caption属性,而标签控件确实具有Caption属性。

您有几个选项可以修复您的第二个循环。 1)您可以将formTab声明为Tab控件(我不确定它的名称是什么)。 Tab控件应具有Caption属性。 2)如果activeTabs中的每个控件都不是Tab控件(在这种情况下,你应该称之为activeControls而不是activeTabs),你可以在循环中检查是否formTab实际上是一个Tab控件。如果是,则将其强制转换为Tab控件,然后调用.Caption。在将其转换为Tab控件之前,VBA不会知道它具有Caption属性,因为常规Control对象没有标题属性。

最后,您可以像在第一个循环中一样使用对象,并让运行时找出要做的事情,但这会给性能带来很大的不利影响。通常,最好使用强类型语言处理特定类型。它还有助于在您的代码中显示您明确知道您正在使用的内容,而不是将其留给运行时来决定您可以使用哪些属性和方法。