![](/img/trans.png)
[英]Macro works when stepping through, but when running, it seems to skip steps
[英]Macro only works when stepping through
以下宏僅在我單步執行時才有效,否則它會跳過刪除數據表中一行的非常重要的行。 關於為什么的任何建議?:/
Public table As ListObject
Public project_code As String
Public Row_Number As Integer
Public sheet As Worksheet
Public myCol As New Collection
Sub UpdateProject_Utveckling()
Set sheet = Database_Utveckling
Set table = sheet.ListObjects("Table_Utveckling") ' "Table_Utveckling" is a table
project_code = InputSheet_Utveckling.Range("RemoveProject") ' "InputSheet_Utveckling is a worksheet
DeleteProjectUtveckling table, project_code, myCol, sheet
AddProject_Utveckling 'Probably not essential for the Q
Set myCol = Nothing ' This is a collection
End Sub
Sub DeleteProjectUtveckling(table As ListObject, project_code As String, myCol As Collection, sheet As Worksheet)
Dim tableColumn As Range
Set table = Database_Utveckling.ListObjects("Table_Utveckling")
Set tableColumn = table.ListColumns("Projektkod").DataBodyRange ' "Projektkod" is a column in
For Each rng_1 In tableColumn
If project_code = rng_1 Then
Row_Number = rng_1.Row
Exit For
Else
End If
Next rng_1
sheet.Rows(Row_Number).Delete ' It skips this line when I run it (not when I step through
End Sub
這真讓我抓狂。 我已經嘗試過“DoEvents”並創建了一個單獨的宏,它只處理“刪除”部分但沒有運氣。
VBA 不會“跳過”任何代碼行,它只是不能那樣工作:肯定有更好的、可證明的解釋——很可能是For Each
循環體邏輯中的一個細微錯誤,導致Row_Number
保持錯誤價值。
我建議通過利用ListObject
API 並擺脫Row_Number
變量來簡化循環邏輯以使其更明顯正確......並將這些全局聲明移動到它們實際使用和相關的唯一過程中。
旁注:所有這些下划線和大小寫不一致都會讓人分心; 考慮堅持使用PascalCase
為成員名稱和camelCase
為當地人。
Set table = Database_Utveckling.ListObjects("Table_Utveckling")
為什么要重新分配調用者已經給出的參數? 讓我們重寫這個過程——將邏輯提取到它自己的 scope 中是一個非常好的決定——你需要盡可能少的小型、專門的程序。 我們想做什么? 給定projectCode
從ListObject
中刪除特定行。 所以我們的輸入需要包含一個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
如果保證該表不包含任何重復的項目代碼,那么我們就完成了 - 我們可以無緣無故地迭代行的 rest,或者像您一樣聰明並立即退出。
所以重寫的過程變成了:
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
現在,該錯誤處理將起作用,但如果在 scope 中發生任何意外情況,我們將收到有關未找到列的誤導性和令人困惑的消息。 讓我們解決這個問題。
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
這個小 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
僅僅通過提取一個小的 function,我們已經將模棱兩可的錯誤處理轉變為標准控制流( If...End If
),並明確表示該過程中引發的任何運行時錯誤都是完全出乎意料的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.