@ Предложение Тима Лентина очень хорошее и, по-моему, прямо отвечает на ваш вопрос.
Но я бы, наверное, никогда не написал подпрограмму, которая оперирует всей коллекцией элементов управления формы. Причина в том, что это на самом деле довольно неэффективно. Но будет ли это уместно, зависит от того, как часто и когда вы ходите по этой коллекции.
Если вы проходите его один раз в событии OnLoad формы (вы не захотите делать это в OnOpen, потому что привязанные к данным свойства элементов управления не обязательно будут полностью инициализированы в этот момент - вы хотя он все еще может работать со свойствами формата - но все готово к работе к моменту запуска события OnLoad), в этом нет ничего особенного, и передача этой коллекции во внешнюю подпрограмму была бы уместной.
Но если вы пройдете по каждой записи (скажем, чтобы скрыть / показать элементы управления или инициализировать поля критериев в несвязанном интерфейсе запроса по форме), то вы значительно улучшите производительность своей формы, используя одну или несколько пользовательские коллекции, имеющие намного меньшее количество элементов для циклического прохождения, чем в любой коллекции элементов управления любой нормальной формы. Затем вы могли бы переписать код Тима, чтобы использовать пользовательскую коллекцию, или, если на то пошло, все равно можно использовать вышеуказанную переменную 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
В этом случае мой метод определения того, какие элементы управления добавляются в коллекцию, заключается в установке свойства Tag этих элементов управления. Вы также можете сделать что-то вроде:
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
Чтобы использовать это, вы можете, например, создать коллекцию элементов управления Nullable, например:
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
К сожалению, использование статической переменной при приятном избегании переменных уровня модуля означает, что ваша подпрограмма инициализации становится менее эффективной, поскольку нет никакой возможности для внешней подпрограммы инициализации использовать эти статические переменные для наполнения всего одним прогоном элементов управления коллекция.
Итак, я не использую пользовательские свойства для этих коллекций, даже если бы хотел. С другой стороны, если бы у меня была только одна коллекция пользовательских элементов управления, я бы это сделал.
Во всяком случае, я бродил слишком долго и со слишком большой сверткой, и, вероятно, весь этот воздушный код заполнен ошибками ...