收到“无效使用财产”#39;从VBA Access中的函数返回数据类型时出错?

时间:2018-03-14 20:50:44

标签: vba access-vba

我创建了一个尝试返回SubForm数据类型的函数。各种父Forms使用此函数。

该功能如下所示:

Public Function mySubFrm(name As String, subformName As String) As SubForm

    Dim frm As Form
    Dim subFrm As SubForm

    Set frm = Forms(name)
    Set subFrm = frm.Controls(subformName)

    mySubFrm = subFrm

End Function

我试图通过以下方式使用它:

Dim testSubForm As SubForm

testSubForm = mySubFrm("testForm", "testSubForm")

立即出现编译错误:

  

无效使用财产

我尝试做的是在frm.Controls(subformName)添加一个监视,我看到它的返回类型是SubForm/SubForm,所以我觉得我正在声明并设置正确的数据类型,但是我又不确定了吗?

有人可以帮我解决我做得不好的事吗?

由于

3 个答案:

答案 0 :(得分:4)

我不太了解Access,但我很了解VBA。

您的函数正在返回对象引用:

Public Function mySubFrm(name As String, subformName As String) As SubForm

因此,必须使用Set关键字指定其返回值

Set mySubFrm = subFrm

你之所以得到这个令人困惑的错误,是因为VBA中的一个可爱(不是!)的东西叫做默认属性

请参阅,表单具有默认属性,很可能是其Controls集合 - 并且该属性仅公开Public Property Get访问者,这使其成为只读。

因此,当您省略Set关键字时:

mySubFrm = subFrm

VBA认为代码是合法的,因此你唯一想做的就是分配那个默认属性 - 换句话说,它的行为就像你写的一样:

mySubFrm.Controls = subFrm

但是Controls班级'自己的默认属性是Item成员,它也是只读的:默认Controls属性不能出现在作业的左侧。

因此,无效使用属性

我的开源项目Rubberduck将很快进行检查,只要您隐式引用对象的默认属性,即可提供明确的调用。编写代码表示它所做的事情并执行它所说的的代码很难在你甚至不知道你指的是默认属性时。

答案 1 :(得分:2)

您收到错误是因为您尝试设置对象,但未使用Set关键字。

也许应该如下:

Set mySubFrm = subFrm

或者

Set mySubFrm = frmDatasheet

答案 2 :(得分:1)

我想建议一种不同的方法。通常,当您使用子表单创建表单时,实际上您需要子表单是动态的很少见。父表单和子表单之间几乎总是存在关系,我会考虑父表单,而不会让子表单成为破坏的对象。

因此,当我需要访问子表单上的内容时,我更喜欢使用显式版本:

Dim mySubForm As Access.SubForm
Set mySubForm = Me.Controls("mySubForm").Form

mySubForm.SomeControlOnMySubForm.Value = 123

是的,它现在有3行,但优点是现在在父表单中明确指出对特定表单的引用。您现在可以从代码中看到父表单依赖于 子表单。更重要的是,如果删除或重命名控件SomeControlOnMySubform,上面的表单将允许VBA编译器警告您子窗体上没有这样的对象,使您能够验证代码。

换句话说,尽量将任何潜在的运行时错误转换为编译时错误,因为编译时错误比运行时错误更容易验证和防止。

同样的原则恰恰相反;如果要根据父表单显式描述子表单,可以执行以下操作:

Dim myParent As Form_frmParent
Set myParent = Me.Parent

注意:代码都假定所涉及的所有表单都有代码隐藏。如果表单没有代码隐藏,则它不会有VBA类供您引用。在这种情况下,我将表单的属性HasModule(位于Others标签中)设置为Yes,即使最终没有代码隐藏。 (原因是它曾经是你可以创建"轻量级"形式通过创建它没有代码隐藏但使用现代硬件,几乎没有任何区别)