为什么Workbook.Close触发UserForm_Terminate? – VBA

下面的代码有一些问题,这让我很生气。 我似乎无法find代码突然结束时Excel Workbook被自动closures的原因。

该代码是从Excel工作簿中执行的,其工作原理如下:

  • 它打开另一个工作簿(WbLOP)
  • 创build第三个工作簿(TargetWb)
  • 从WbLOP复制一些数据到TargetWb
  • closuresWbLOP

下面的整个代码:

 Public WbLOP As Workbook, WsLop As Worksheet Public AbtToEval As String Sub Std_Ausw() Dim OpenDialog As Object, FileName As String Dim Ws As Worksheet Dim Termin As Date Dim TargetWb As Workbook, TargetWs As Worksheet Dim i As Integer, j As Integer, k As Integer, w As Integer Dim ZielCol As Integer, ZielNEWCol As Integer, PEPStatusCol As Integer, StatusAICol As Integer Dim ActivityRow As Integer ' Asks user input file to read from Set OpenDialog = Application.FileDialog(msoFileDialogFilePicker) With OpenDialog .AllowMultiSelect = False .Filters.Clear .Filters.Add "Excel Files", "*.xls, *.xlsx, *.xlsm" If .Show Then FileName = .SelectedItems(1) Else Set OpenDialog = Nothing Exit Sub End If End With Set OpenDialog = Nothing ' Checks if the worksheet "LOP" is contained in the file Set WbLOP = Application.Workbooks.Open(FileName) For Each Ws In WbLOP.Worksheets If UCase(Ws.Name) = "LOP" Then Set WsLop = Ws Exit For End If Next On Error Resume Next If WsLop.Name = "" Then WbLOP.Close savechanges:=False Set WbLOP = Nothing MsgBox "Fail" Exit Sub End If On Error GoTo 0 ' Shows a Userform to let user decide the name of the AbtToEval Ausw.Show 

我在这里粘贴UserForm的代码:

 Private Sub Cancel_Click() End End Sub Private Sub UserForm_Terminate() End End Sub Private Sub UserForm_Initialize() Dim Abt() As String Dim i As Integer, j As Integer, k As Integer ' Searches for the PD-Abt column i = 1 Do Until LCase(WsLop.Cells(8, i)) = "pd-abt" i = i + 1 Loop ' Copies the unique Abt in an array j = 10 ReDim Abt(0) Abt(0) = UCase(WsLop.Cells(j, i)) Do Until IsEmpty(WsLop.Cells(j, 1)) For k = 0 To UBound(Abt) If Abt(k) = UCase(WsLop.Cells(j, i)) Then Exit For Else If k = UBound(Abt) Then ReDim Preserve Abt(UBound(Abt) + 1) Abt(UBound(Abt)) = UCase(WsLop.Cells(j, i)) End If End If Next j = j + 1 Loop ' Initializes the combo-box with the Abt names For i = 0 To UBound(Abt) Me.AbtBox.AddItem Abt(i) Next Me.AbtBox.ListIndex = 0 End Sub Private Sub OK_Click() AbtToEval = Me.AbtBox.List(Me.AbtBox.ListIndex) Me.Hide End Sub 

在这里,主子被恢复

 ' Opens a new workbook and copies the table from the template Application.DisplayAlerts = False Set TargetWb = Application.Workbooks.Add Do Until TargetWb.Sheets.Count = 1 TargetWb.Sheets(TargetWb.Sheets.Count).Delete Loop Set TargetWs = TargetWb.Sheets(1) ThisWorkbook.Worksheets("Template").Range("A1:J3").Copy Destination:=TargetWs.Range("A1") Application.DisplayAlerts = True TargetWs.Range("A2") = AbtToEval ' Sets a standard limit of 4 weeks from today Termin = DateAdd("ww", 4, Date) ' Searches for the Ziel-Datum columns i = 1 Do Until InStr(1, LCase(WsLop.Cells(8, i)), "ziel-datum") <> 0 i = i + 1 Loop If InStr(1, LCase(WsLop.Cells(8, i)), "neu") <> 0 Then ZielNEWCol = i i = i + 1 Do Until InStr(1, LCase(WsLop.Cells(8, i)), "ziel-datum") <> 0 i = i + 1 Loop ZielCol = i Else ZielCol = i i = i + 1 Do Until InStr(1, LCase(WsLop.Cells(8, i)), "ziel-datum") <> 0 i = i + 1 Loop ZielNEWCol = i End If ' Searches for the status columns i = 1 Do Until InStr(1, LCase(WsLop.Cells(8, i)), "pep status") <> 0 i = i + 1 Loop PEPStatusCol = i i = 1 Do Until InStr(1, LCase(WsLop.Cells(8, i)), "status ai") <> 0 i = i + 1 Loop StatusAICol = i ' Searches for the activities to do i = 0 j = 0 Do Until IsEmpty(WsLop.Cells(9 + i, 1)) If Not WsLop.Cells(9 + i, PEPStatusCol) = "akt" Then GoTo Go_Forth If WsLop.Cells(9 + i, StatusAICol) = "ges" Then GoTo Go_Forth If IsEmpty(WsLop.Cells(9 + i, ZielNEWCol)) Then If CDate(WsLop.Cells(9 + i, ZielCol)) > Termin Then GoTo Go_Forth Else ActivityRow = 9 + i End If Else If CDate(WsLop.Cells(9 + i, ZielNEWCol)) > Termin Then GoTo Go_Forth Else ActivityRow = 9 + i End If End If ThisWorkbook.Worksheets("Template").Range("A4:J4").Copy Destination:=TargetWs.Cells(4 + j, 1) For w = 1 To 10 k = 1 Do Until TargetWs.Cells(3, w) = WsLop.Cells(8, k) k = k + 1 Loop TargetWs.Cells(4 + j, w) = WsLop.Cells(ActivityRow, k) Next j = j + 1 Go_Forth: i = i + 1 Loop ' If TargetSheet is empty then shows only a message If IsEmpty(TargetWs.Cells(4, 1)) Then Application.DisplayAlerts = False TargetWb.Close savechanges:=False Application.DisplayAlerts = True MsgBox "We have no bananas before " & Format(Termin, "dd.mm.yyyy") & " for the " & AbtToEval & "!", vbInformation, AbtToEval & " out of bananas" Else ' If the activity is in the past, it is marked in red i = 4 Do Until IsEmpty(TargetWs.Cells(i, 1)) If IsEmpty(TargetWs.Cells(i, 2)) Then If CDate(TargetWs.Cells(i, 1)) <= Date Then TargetWs.Range(Cells(i, 1).Address(0, 0), Cells(i, 10).Address(0, 0)).Font.ColorIndex = 3 Else If CDate(TargetWs.Cells(i, 2)) <= Date Then TargetWs.Range(Cells(i, 1).Address(0, 0), Cells(i, 10).Address(0, 0)).Font.ColorIndex = 3 End If i = i + 1 Loop ' Fixes the visual and adds filters TargetWs.Range("A4").Select ActiveWindow.FreezePanes = True TargetWs.Range("A3:J3").AutoFilter TargetWs.Cells.EntireColumn.AutoFit End If ' Ending Set TargetWs = Nothing Set TargetWb = Nothing Set WsLop = Nothing WbLOP.Close savechanges:=False Set WbLOP = Nothing End Sub 

我试图find一个解决方法, if WbLOP Is Nothing Then EndUserForm_Terminate事件if WbLOP Is Nothing Then End ,正如在一些评论/答案指出正在触发Workbook.Close事件,但显然,如果我执行的代码,而TargetWbclosures,而不是, 什么都没发生。
事件基本上与WbLOP.Close ,我仍然不明白为什么。

因为你还没有发布完整的代码 – 在debugging模式下运行你的代码。 在你想仔细观察发生的事情的地方添加断点。 使用F5运行(在下一个断点停止或运行直到结束)和F8为步进模式(移到下一行)。 使用监视表来检查variables的值或整个IF连续性,以确定代码何时应该分支或做特定的事情。

debugging模式:

代码调试

编辑

在这种情况下,有没有可能像过去的问题一样 ?

在这里输入图像说明

编辑2

根据MSDN :

MSDN

当对象被卸载时终止事件被触发。 第一个工作簿closures工作确定,因为表单尚未加载。 如果表单是该工作簿在执行工作簿closures时的对象,则它将卸载该表单并触发UserForm_Terminate,从而导致END代码停止执行。

显然这将会在每次closures的时候执行(甚至隐藏它)

 Private Sub userform_terminate() 'Code End Sub 

你应该使用这个来检测当用户用xbuttonclosures它时:

 Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) If CloseMode = 0 Then ' =0 or = vbFormControlMenu 'Code End If End Sub 

然后它只会在用户closures表单时执行,而不是在表单被卸载时执行,所以用上面的替代方法replace你的userform_terminate ,它应该工作正常。