簡體   English   中英

宏僅在單步執行時有效

[英]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 中是一個非常好的決定——你需要盡可能少的小型、專門的程序。 我們想做什么? 給定projectCodeListObject中刪除特定行。 所以我們的輸入需要包含一個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM