Цикл
A For Each
будет перебирать элементы управления в порядке их добавления в форму (хотя я не думаю, что это указано или гарантировано каким-либо образом), как это было бы с любым другим типом Collection
.
For Each
работает, потянув перечислитель коллекции . Если вы посмотрите на MSForms.Controls
в Обозревателе объектов (F2), щелкните правой кнопкой мыши пустую область в обозревателе объектов и установите флажок «Показать скрытых участников», вы увидите скрытый _NewEnum
член по типу.
_NewEnum
также существует в Excel.Workbooks
, Excel.Range
, VBA.Collection
, и во всем остальном, что вы можете выполнить с помощью цикла For Each
: если вы пишете собственный класс коллекции, вам нужно иметь NewEnum() As IUnknown
элемент со специальным атрибутом member (VB_UserMemId = -4
) - этот перечислитель - это то, что среда выполнения VBA использует для получения следующей ссылки на объект в коллекции.
И он ничего не знает о TabIndex
элемента управления. TabIndex
определяет порядок элементов управления, чтобы получить фокус, когда пользователь нажимает клавишу Tab для итерации элементов управления - это не имеет ничего общего с циклом For Each
.
Если вам нужно выполнить итерации элементов управления в определенном порядке (FWIW, я не могу придумать разумную причину для этого), то вы можете указать порядок в самих именах элементов управления (например, txtSomethingSomething1
, txtSomethingSomething2
, ...), а затем извлекают элементы управления по имени, используя цикл For...Next
(что было бы менее эффективно, поскольку наборы объектов хотят, чтобы было перечисляемым ):
Dim i As Long
Dim currentTextBox As TextBox
For i = 1 To 20
Set currentTextBox = Me.Controls("txtSomethingSomething" & i)
currentTextBox.Value = Application.WorksheetFunction.VLookup(...)
Next
В качестве альтернативы, вы можете сохранить необходимый ColumnN
индекс в свойстве Tag
каждого элемента управления - и получить гораздо более эффективную часть логики (хотя можно поспорить о надежности), есть много способов сделать это, это просто один способ):
For Each ctrl In Me.Controls
If ctrl.Tag <> vbNullString Then
columnN = ctrl.Tag
ctrl.Value = Application.WorksheetFunction.VLookup(...)
End If
Next
Обратите внимание, что я использовал Me.Controls
вместо PipelineUpdateForm.Controls
; Я предполагаю, что этот код находится внутри кода формы - если это так, то вы должны ссылаться на экземпляр формы с ключевым словом Me
, а не именем формы. Рано или поздно вы неизбежно столкнетесь с довольно распространенными проблемами, если продолжите ссылаться на экземпляр формы по умолчанию в коде этой формы. Моя UserForm1.Show статья прошлого октября охватывает все это в деталях.
Дополнительное замечание: вы, вероятно, захотите вставить Sheets("PipelineRawEntries").Range("B2:AS4")
в локальную переменную объекта, вместо разыменования одного и того же объекта снова и снова на каждой итерации цикла:
Dim lookupRange As Range
Set lookupRange = ActiveWorkbook.Workheets("PipelineRawEntries").Range("B2:AS4")
А затем используйте lookupRange
в функции VLookup
.