3 回答
TA贡献1875条经验 获得超5个赞
尽管已(以前)接受了该问题的答案,但该爆炸实际上并不是成员或集合访问运算符。它做了一件简单而又具体的事情:bang运算符通过将bang运算符后的文字名称作为字符串参数传递给该默认成员,从而提供对对象默认成员的后期绑定访问。
而已。该对象不必是集合。它不必具有称为的方法或属性Item。它所需要的只是一个Property Get或Function可以接受字符串作为第一个参数的参数。
有关更多详细信息和证明,请参阅我的博客文章讨论:爆炸!VBA中的(感叹号运算符)
TA贡献1817条经验 获得超6个赞
一对陷阱可作为已发布的两个出色答案的补充:
访问表单与报表中
的记录集字段 Access中Form对象的默认项是表单的Controls集合和表单记录集的Fields集合的并集。如果控件的名称与字段的名称冲突,则不确定实际返回哪个对象。由于字段和控件的默认属性都是它们的.Value,因此通常是“无区别的区分”。换句话说,通常不关心它是因为字段和控件的值通常是相同的。
当心命名冲突!
Access的“表单和报表”设计器默认将绑定控件的命名与绑定到的记录集字段的命名相同,从而加剧了这种情况。我个人采用了使用控件类型前缀重命名控件的约定(例如,tbLastName绑定到LastName字段的文本框)。
报表记录集字段不存在!
我之前说过Form对象的默认项是Controls和Fields的集合。但是,报表对象的默认项目只是其控件集合。因此,如果要使用bang运算符引用记录集字段,则需要将该字段包括为绑定控件(如果需要的话)的源。
当心与显式表单/报表属性发生冲突
当将控件添加到表单或报表中时,Access会自动创建引用这些控件的属性。例如,tbLastName通过引用可以从表单的代码模块中获得名为的控件Me.tbLastName。但是,如果Access与现有表单或报表属性冲突,它将不会创建此类属性。例如,假设添加了一个名为Pages的控件。Me.Pages在窗体的代码模块中引用将返回窗体的Pages属性,而不是名为“ Pages”的控件。
在此示例中,可以Me.Controls("Pages")使用bang运算符显式或隐式访问“ Pages”控件Me!Pages。但是请注意,使用bang运算符意味着,如果表单的记录集中存在一个Access字段,则它可能会返回一个名为“ Pages”的字段。
那.Value呢?
尽管未在问题中明确提及,但以上评论中提到了该主题。字段对象和大多数“可数据绑定”¹控件对象的默认属性是.Value。由于这是默认属性,因此通常总是明确地将其包括在内不必要地冗长。因此,这是标准做法:
Dim EmployeeLastName As String
EmployeeLastName = Me.tbLastName
代替:
EmployeeLastName = Me.tbLastName.Value
键入字典时,请注意细微的.Value错误。在
某些情况下,此约定可能会导致细微的错误。我实际上在实践中碰到的最引人注目的(如果只有内存可用的话)是在将“字段/控件”的值用作“字典”键时使用的。
Set EmployeePhoneNums = CreateObject("Scripting.Dictionary")
Me.tbLastName.Value = "Jones"
EmployeePhoneNums.Add Key:=Me.tbLastName, Item:="555-1234"
Me.tbLastName.Value = "Smith"
EmployeePhoneNums.Add Key:=Me.tbLastName, Item:="555-6789"
人们可能希望上面的代码在EmployeePhoneNums字典中创建两个条目。而是在最后一行抛出错误,因为我们正在尝试添加重复键。即,tbLastName控件对象本身是键,而不是控件的值。在这种情况下,控件的值甚至无关紧要。
实际上,我希望对象的内存地址(ObjPtr(Me.tbLastName))可能是幕后用来索引字典的内容。我做了一个快速测试,似乎证实了这一点。
'Standard module:
Public testDict As New Scripting.Dictionary
Sub QuickTest()
Dim key As Variant
For Each key In testDict.Keys
Debug.Print ObjPtr(key), testDict.Item(key)
Next key
End Sub
'Form module:
Private Sub Form_Current()
testDict(Me.tbLastName) = Me.tbLastName.Value
Debug.Print ObjPtr(Me.tbLastName); "..."; Me.tbLastName
End Sub
运行上面的代码时,每次关闭并重新打开表单时,都会添加一个词典项。从一个记录移到另一个记录(并因此导致对Form_Current例程的多次调用)不会添加新的词典项,因为它是Control对象本身索引该词典,而不是Control的值。
我的个人建议/编码约定
多年来,我采用了以下做法,即YMMV:
与控制型指标前缀窗体/报表控件名称(如tbTextBox,lblLabel等)
使用Me.符号(例如Me.tbLastName)引用代码中的表单/报表控件
避免创建与表/查询字段有问题的名字摆在首位
Me!发生冲突时(例如,与旧版应用程序(例如Me!Pages))使用符号
包括隐藏的报表控件以访问报表Recordset字段值
.Value仅在情况需要增加详细程度时才明确包括(例如,词典键)
¹ 什么是“数据可绑定”控件?
基本上是具有ControlSource属性的控件,例如TextBox或ComboBox。不可绑定的控件将类似于Label或CommandButton。TextBox和ComboBox的默认属性为.Value; 标签和命令按钮没有默认属性。
添加回答
举报