@Tim Lentine的建議是非常好的,直接回答你的問題,在我看來。
但我可能永遠不會寫一個操作整個控件集合的表單子。原因是這樣做實際上效率很低。但是否合適取決於你走路的頻率和時間。
如果您在窗體的OnLoad事件中漫遊一次(您不希望在OnOpen中執行此操作,因爲控件的數據綁定屬性無法保證在此時完全初始化 - 儘管你仍然可以對格式屬性進行操作 - 但是在OnLoad事件觸發時,所有事情都已準備就緒),這沒什麼大不了的,並且將該集合傳遞給外部子例程將是合適的。但是,如果您正在爲每條記錄散步(比如隱藏/顯示控件,或者在未綁定的逐個表單界面中初始化條件字段),那麼您將顯着提高表單的性能,方法是使用一個或多個更多自定義集合的循環數量要比任何常規窗體的控件集合中少得多。然後你可以重寫Tim的代碼來使用自定義集合,或者,對於這個問題,仍然可以使用上面的Object變量並將它傳遞給一個自定義集合(並且仍然可以將它傳遞給一個表單的控件集合)。
基本上,你要做的是在窗體的OnLoad事件中初始化集合。我通常寫一個私人子程序要做到這一點,所以我可以重新初始化應該一碼復位發生:
Private Sub SetupCollections()
If mcolCriteria.Count = 0 Then
Call PopulateCollections(Me, mcolCriteria, "Criteria")
End If
End Sub
Public Sub PopulateCollections(frm As Form, pcol As Collection, strTag As String)
Dim ctl As Control
For Each ctl In frm.Controls
If ctl.Tag = strTag Then
pcol.Add ctl, ctl.Name
End If
Next ctl
Set ctl = Nothing
End Sub
在這種情況下,我確定哪些控制被添加到集合的方法是設置的標記屬性這些控件。你也可以這樣做:
Public Sub PopulateCollections(frm As Form, pcol As Collection, intControlType As AcControlType)
Dim ctl As Control
For Each ctl In frm.Controls
If ctl.ControlType = intControlType
pcol.Add ctl, ctl.Name
End If
Next ctl
Set ctl = Nothing
End Sub
要使用此,你可以,比如,創建可空控制的這樣一個集合:
If mcolControlsNullable.Count = 0 Then
Call PopulateCollections(Me, mcolControlsNullable, acTextBox)
Call PopulateCollections(Me, mcolControlsNullable, acComboBox)
Call PopulateCollections(Me, mcolControlsNullable, acListBox)
End If
對於布爾控件:
If mcolControlsBoolean.Count = 0 Then
Call PopulateCollections(Me, mcolControlsBoolean, acCheckBox)
End If
對於具有默認值的選項組或其他控件:
If mcolControlsWithDefaults.Count = 0 Then
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acTextBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acComboBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acListBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acCheckBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acOptionGroup)
End If
Public Sub PopulateCollectionsWithDefaults(frm As Form, pcol As Collection)
Dim ctl As Control
For Each ctl In frm.Controls
If Len(ctl.DefaultValue) > 0 Then
pcol.Add ctl, ctl.Name
End If
Next ctl
Set ctl = Nothing
End Sub
Private Sub SetControlValuesFromDefaults(pcol As Collection)
For Each ctl in pcol
ctl = ctl.DefaultValue
Next ctl
End Sub
而對於其他集合:
Public Sub SetControlValues(pcol As Collection, varValue As Variant)
For Each ctl in pcol
ctl = varValue
Next ctl
End Sub
有了這個更復雜的集藏品,你需要這樣的事情最初填充它們其中:
Private Sub SetupCollections()
If mcolControlsNullable.Count = 0 Then
Call PopulateCollections(Me, mcolControlsNullable, acTextBox)
Call PopulateCollections(Me, mcolControlsNullable, acComboBox)
Call PopulateCollections(Me, mcolControlsNullable, acListBox)
End If
If mcolControlsBoolean.Count = 0 Then
Call PopulateCollections(Me, mcolControlsBoolean, acCheckBox)
End If
If mcolControlsWithDefaults.Count = 0 Then
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acTextBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acComboBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acListBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acCheckBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acOptionGroup)
End If
End Sub
...然後你會想子來初始化控制值:
Private Sub InitializeControls()
Call SetControlValues(mcolControlsNullable, Null)
Call SetControlValues(mcolControlsBoolean, False)
Call SetControlValuesFromDefaults(mcolControlsWithDefaults)
End Sub
...所以,你可以一切都在你的窗體的onload事件然後設置:
Call SetupCollections()
Call InitializeControls()
現在,當然,有更少的複雜方式來做到這一點。你可能希望你的初始化程序走控件集合只有一次:
Private Sub SetupCollections()
Dim ctl As Control
For Each ctl in Me.Controls
If Len(ctl.DefaultValue) > 0 then
mcolControlsWithDefaults.Add ctl, ctl.Name
Else
Select Case ctl.ControlType
Case acTextBox, acComboBox, acListBox
mcolControlsNullable.Add ctl, ctl.Name
Case acCheckBox
mcolControlsBoolean.Add ctl, ctl.Name
End Select
End If
Next ctl
Set ctl = Nothing
End Sub
消除初始化程序是使用自定義屬性返回集合的一種方法,使用將被重新初始化內部靜態變量如所須。然而,這將意味着通過控件集合多個階層,所以它的效率不高:
Private Property Get colControlsNullable() As Collection
Static colNullable As Collection
If colNullable.Count = 0 Then
Call PopulateCollections(Me, mcolControlsNullable, acTextBox)
Call PopulateCollections(Me, mcolControlsNullable, acComboBox)
Call PopulateCollections(Me, mcolControlsNullable, acListBox)
End If
Set colControlsNullable = colNullable
End Property
不幸的是,使用靜態變量,同時很好地避免了模塊級的變量,意味着你的inialization例行變得效率較低,因爲外部初始化例程無法利用這些靜態變量來通過一次遍歷控件集合來填充所有內容。
所以,我不使用這些集合的自定義屬性,即使我希望我可以。另一方面,如果我只有一個自定義控件集合,我會這樣做。
無論如何,我洋洋灑灑遠長,用了太多的卷積,大概所有的空氣代碼充滿了錯誤...
我走了一個不同的方向,但這可能是理想的方式去。 – KeithA