VBA не «пропускает» какие-либо строки кода, он просто не работает таким образом: определенно есть лучшее доказуемое объяснение - очень вероятно, что есть небольшая ошибка в логике тела цикла For Each
, которая вызывает Row_Number
для хранения неправильного значения.
Я бы предложил упростить логику цикла, чтобы сделать ее более очевидно правильной, используя API ListObject
и избавившись от переменной Row_Number
... и переместив ихглобальные декларации к единственной процедуре, в которой они фактически используются и имеют отношение.
Примечание: все эти подчеркивания и несоответствия в корпусе довольно отвлекают;рассмотрите возможность придерживаться PascalCase
для имен членов и camelCase
для локальных.
Set table = Database_Utveckling.ListObjects("Table_Utveckling")
Почему вы переназначаете параметр, который вы уже дали вызывающей стороне?Давайте перепишем эту процедуру - выделение этой логики в ее собственную область было ОЧЕНЬ хорошим решением - вам нужны небольшие специализированные процедуры, которые делают как можно меньше.Что мы пытаемся сделать?Удалите определенные строки из ListObject
, учитывая projectCode
.Таким образом, наши входные данные должны включать ListObject
и String
- и нам больше ничего не нужно:
Private Sub DeleteProjectUtveckling(ByVal table As ListObject, ByVal projectCode As String)
End Sub
Обратите внимание, что процедура Private
, так как ей не нужнобыть Public
.И поскольку все параметры являются очень стандартными входами , мы можем передать их ByVal
.
Первое, что нам нужно сделать, это найти столбец в table
, который может содержатьprojectCode
.А поскольку столбец может отсутствовать в предоставленной таблице, нам нужно проверить, что он есть.
Private Sub DeleteProjectUtveckling(ByVal table As ListObject, ByVal projectCode As String)
On Error GoTo CleanFail
Dim projectCodeColumnIndex As Long
projectCodeColumnIndex = table.ListColumns("Projektkod").Index
'...todo...
CleanExit:
Exit Sub
CleanFail:
MsgBox "Column 'Projektkod' was not found in table '" & table.Name & "'."
Resume CleanExit
End Sub
Далее нам нужно перебрать строки таблицы и определить, нашли ли мы код проекта.
Dim currentRow As ListRow
For Each currentRow In table.ListRows
If currentRow.Range.Cells(ColumnIndex:=projectCodeColumnIndex).Value = projectCode Then
'...todo...
End If
Next
Что приятно в ListRow
, так это то, что он уже знает, как удалить себя: нам не нужно заботиться о каком-либо номере строки или строках листа:
currentRow.Delete
Если в таблице гарантированно не содержится повторяющихся кодов проекта, то все готово - мы можем перебрать оставшиеся строки без причины или проявить смекалку и немедленно выручить, как вы.
Так чтопереписанная процедура становится:
Private Sub DeleteProjectUtveckling(ByVal table As ListObject, ByVal projectCode As String)
On Error GoTo CleanFail
Dim projectCodeColumnIndex As Long
projectCodeColumnIndex = table.ListColumns("Projektkod").Index
Dim currentRow As ListRow
For Each currentRow In table.ListRows
If currentRow.Range.Cells(ColumnIndex:=projectCodeColumnIndex).Value = projectCode Then
currentRow.Delete
Exit For
End If
Next
CleanExit:
Exit Sub
CleanFail:
MsgBox "Column 'Projektkod' was not found in table '" & table.Name & "'."
Resume CleanExit
End Sub
И вызывающий код становится:
DeleteProjectUtveckling table, project_code
Теперь эта обработка ошибок будет работать, но если в этой области произойдет что-то неожиданное, мы будемполучить вводящее в заблуждение и сбивающее с толку сообщение о том, что столбец не найден.Давайте исправим это.
Private Function TryGetColumnIndex(ByVal table As ListObject, ByVal columnName As String, ByRef outIndex) As Boolean
On Error Resume Next
outIndex = table.ListColumns(columnName).Index
TryGetColumnIndex = (Err.Number = 0)
On Error GoTo 0
End Function
Эта небольшая функция имеет одну единственную цель: получить индекс столбца, учитывая таблицу и имя столбца.Он вернет True
, если это работает, False
, если это не так, и когда это сработает, аргумент outIndex
будет содержать индекс столбца, который мы ищем.
Теперь мы можем написатьПроцедура удаления строки выглядит следующим образом:
Private Sub DeleteProjectUtveckling(ByVal table As ListObject, ByVal projectCode As String)
On Error GoTo CleanFail
Dim projectCodeColumnIndex As Long
If Not TryGetColumnIndex(table, "Projektkod", outIndex:=projectCodeColumnIndex) Then
MsgBox "Column 'Projektkod' was not found in table '" & table.Name & "'."
Exit Sub
End If
Dim currentRow As ListRow
For Each currentRow In table.ListRows
If currentRow.Range.Cells(ColumnIndex:=projectCodeColumnIndex).Value = projectCode Then
currentRow.Delete
Exit For
End If
Next
CleanExit:
Exit Sub
CleanFail:
MsgBox "Unexpected error: " & Err.Description
Resume CleanExit <~ F9 to place a breakpoint here
Resume '<~ use for step-through debugging. takes you to the instruction that raised the error
End Sub
И, просто извлекая небольшую небольшую функцию, мы превратили обработку неоднозначных ошибок в стандартный поток управления (If...End If
) и дали понять, что любой запускошибка времени, возникшая в этой процедуре, является совершенно неожиданной.