VBA迭代主窗体上的控件,同时忽略子窗体
Posted
技术标签:
【中文标题】VBA迭代主窗体上的控件,同时忽略子窗体【英文标题】:VBA Iterate over controls on main form while ignoring subform 【发布时间】:2015-06-02 14:48:32 【问题描述】:我有一个按钮,用于清除(搜索)表单上的所有活动控件。但是,每个搜索的输出都显示在一个子窗体中,并且似乎是作为文本框实现的。 (虽然它显示为电子表格,但子表单的设计视图显示文本框。)
因此,当我将表单上所有 acTextBox
控件的 Value
设置为 ""
时,它也会清除子表单上的某些内容,并且所有进一步的搜索都会在所有字段中返回 #Name,直到表单重新打开。
此外,在发生此错误时,单击子表单的 Form
对象会生成一条消息警告 Object invalid or no longer set.
尝试编辑关联方法通常会导致表单在设计视图中打开并获得焦点,这可能会或可能会不显着。 (如果设计视图尚未打开,则只要在方法中按下一个键就会发生这种情况。)
问题似乎在以下块中:
Dim ctl As Control
For Each ctl In Me.Controls
If (ctl.ControlType = acTextBox) Then
If Len(ctl.Properties("ControlSource")) = 0 Then
ctl.Value = "" '***
End If
ElseIf ctl.ControlType = acCheckBox Then
ctl.Value = False
ElseIf ctl.ControlType = acComboBox Then
ctl.Value = ""
End If
Next ctl
'***
后面的赋值是我缩小问题范围的地方,因为注释掉该行可以防止问题发生——但是将文本框的值设置为“”是我我正在尝试做,我不能摆脱它。
ControlSource 长度比较试图从下一行中排除子表单项,因为它们都是绑定的,而主表单项不是。它是嵌套的(与 If (... And ...) 相反),因为 VBA 没有惰性 Or。
需要做些什么来迭代所有主窗体控件而不影响子窗体控件?
编辑:子表单/查询的说明。
子表单使用以下语句从查询中提取数据:
SELECT DW_Query.Map_Number, DW_Query.Map_Name, DW_Query.Map_Type, DW_Query.Town, DW_Query.Address, DW_Query.Street, DW_Query.Block, DW_Query.Lot, DW_Query.group, DW_Query.Folder, DW_Query.Latitude, DW_Query.Longitude FROM DW_Query;
似乎 Town 字段可能会以某种方式被删除,因为有时会有一个 RTE 2465 的实例,can't find the field 'Town' referred to in your expression.
但是,这发生在主窗体的 Form_Open 子中,在以下行中:
Me.DW_Query_subform.Form.RecordSource = "SELECT DW_Query.Map_Number, DW_Query.Map_Name, DW_Query.Map_Type, DW_Query.Town," & _
"DW_Query.Address, DW_Query.Street, DW_Query.Block, DW_Query.Lot, DW_Query.group, DW_Query.Folder, DW_Query.Latitude, DW_Query.Longitude " & _
"FROM DW_Query;" 'Set subform to use address query. (Faster)
【问题讨论】:
记住子窗体是主窗体上的控件。但是它不应该受到影响,因为您正在测试控制类型。你调试过代码吗? 子表单是否设置了子/主字段? 老实说,我并不完全确定您所说的“调试代码”是什么意思;我还不熟悉 Access 中的调试工具。我的编译没有错误,但到目前为止还没有设置断点或对“立即”窗口进行任何操作(因为我不知道该放什么会有帮助)。 基本上,您只需在For Each ctl In Me.Controls
附近的某处放置一个断点,只需单击该行的左侧即可设置断点。代码将停在那里,然后您可以使用 F8“遍历”代码(至少对于 2010 年)。
【参考方案1】:
您需要设置为 Null,因为文本框可能不接受空字符串:
Dim ctl As Control
For Each ctl In Me.Controls
If (ctl.ControlType = acTextBox) Then
If Len(ctl.Properties("ControlSource")) = 0 Then
ctl.Value = Null
End If
ElseIf ctl.ControlType = acCheckBox Then
ctl.Value = False
ElseIf ctl.ControlType = acComboBox Then
ctl.Value = Null
End If
Next ctl
【讨论】:
这是 2007 年的问题,还是有一些文档可以支持?我想看看我的数据库,我有将近 100 个地方,我有ctr.Value = ""
和零个说 ctr.Value = Null
虽然这确实解决了#Name
结果的问题,(不知何故——我必须同意 Newd 的观点,我从未听说过这个问题,其他此类任务也可以正常工作。)相反,它会导致子表单显示它从中提取的数据库的同一子集,而不考虑来自主表单的输入。
这似乎可行,实际上。我根据其他地方的建议进行了其他更改,这似乎使古斯塔夫的建议无效;在还原它们并应用此方法后,原始问题已解决而没有造成任何问题,因此我将其标记为答案。【参考方案2】:
您可以缩小迭代范围,例如仅清除“详细信息”部分中的控件
Dim ctl As Control
For Each ctl In Me.Detail.Controls
If (ctl.ControlType = acTextBox) Then
If Len(ctl.Properties("ControlSource")) = 0 Then
ctl.Value = vbnullString
End If
ElseIf ctl.ControlType = acCheckBox Then
ctl.Value = False
ElseIf ctl.ControlType = acComboBox Then
ctl.Value = Null
End If
Next ctl
【讨论】:
不幸的是,这似乎不起作用。我已将子表单移至页脚部分并遍历Me.Detail.Controls
,但我仍然遇到了我在对 Gustav 的回答的第一条评论中描述的问题。以上是关于VBA迭代主窗体上的控件,同时忽略子窗体的主要内容,如果未能解决你的问题,请参考以下文章
C# Winform主窗体和子窗体之间如何相互操作对方的控件