我遇到竞争条件问题,我有两个QueryTables,每个都挂上了它自己的AfterRefresh事件。每个AfterRefresh事件都会执行一些copy'n'pasting以及一些计算。等待,直到Excel刷新全部(Ctrl + Alt + F5)完成 - VBA
现在,当用户单击刷新所有(Ctrl+Alt+F5)
在Excel中,我希望有每个AfterRefresh处理程序执行,但只有在所有QueryTable刷新完全完成后。
我做StackOverflow上进行搜索,并someone suggested
Activeworkbook.RefreshAll
DoEvents
然而,这是假设,我们以编程方式触发RereshAll。在我的情况下,刷新全部是通过Excel中的内置刷新全部(Ctrl+Alt+F5)
按钮完成的。因此,我没有看到我可以在哪里插入DoEvents
(除非我创建了我自己的“全部刷新”按钮,但我想避免这样做)。
我试图搜索“Excel VBA互斥体”,但我没有找到任何特别的东西。那么,如何在每个AfterRefresh处理程序发生之前确保所有刷新都已完成?
感谢您的阅读!
更新:帮助调试..这里是我的VBA代码。
我有一个模块名为AutoOpen
Dim S As New DataCopy
Dim U As New DataCopy
Sub Auto_Open()
Set S.qt = ThisWorkbook.Sheets(1).QueryTables(2)
S.myWorkbookName = ThisWorkbook.Name
S.sWorksheetProcessName = "ProcessS"
S.sWorksheetDataColumnStart = 1
S.sWorksheetDataColumnEnd = 5
Set U.qt = ThisWorkbook.Sheets(1).QueryTables(1)
U.myWorkbookName = ThisWorkbook.Name
U.sWorksheetProcessName = "ProcessU"
U.sWorksheetDataColumnStart = 6
U.sWorksheetDataColumnEnd = 10
End Sub
我也有一类名为模块DataCopy
Public WithEvents qt As QueryTable
Public myWorkbookName As String
Public sWorksheetProcessName As String
Public sWorksheetDataColumnStart As Integer
Public sWorksheetDataColumnEnd As Integer
Private Sub qt_AfterRefresh(ByVal Success As Boolean)
DataCopier
End Sub
Private Sub DataCopier()
'Debug.Print sWorksheetProcessName & "," & Application.CalculationState
Dim LastNRows As Integer
Dim sWorksheetDataName As String
' How many rows to copy
LastNRows = 297
sWorksheetDataName = "Data"
Application.ScreenUpdating = False
' Clear content in process tab
With Workbooks(myWorkbookName).Worksheets(sWorksheetProcessName)
.Range(.Cells(4, 1), .Cells(.Cells(Rows.Count, 1).End(xlUp).Row, 6)).ClearContents
End With
' Copy to process Tab
With Workbooks(myWorkbookName).Worksheets(sWorksheetDataName)
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
FirstRow = LastRow - LastNRows
If FirstRow < 2 Then
FirstRow = 2
End If
.Range(.Cells(FirstRow, sWorksheetDataColumnStart), .Cells(LastRow, sWorksheetDataColumnEnd)).Copy _
Destination:=Workbooks(myWorkbookName).Worksheets(sWorksheetProcessName).Range("A4")
End With
Debug.Print (sWorksheetProcessName & "," & sWorksheetDataColumnStart & "," & sWorksheetDataColumnEnd)
Application.ScreenUpdating = True
End Sub
由于竞争条件的,只有一个AfterRefresh处理程序成功地copy'n'pasting。另一个不工作,直到我再次单击刷新全部按钮(Ctrl+Alt+F5)
。
也许每个'AfterRefresh'事件处理程序可以以'Activeworkbook.RefreshAll'结尾,后面跟着'DoEvents',也许有一些切换布尔公共变量来阻止回声事件。 –
@JohnColeman,但用户已经点击了内置的全部刷新按钮,所以如果我为每个'AfterRefresh'添加'Activeworkbook.RefreshAll'并不意味着它实质上是刷新两次? 其实,在第二个想法,因为它是在'AfterRefresh'内,它会触发无限循环刷新?因为'AfterRefresh'会触发另一次刷新,这会再次触发'AfterRefresh' – Antony
现在我可以更清楚地看到问题了。也许在每个事件处理程序的开始处包含一个定时器循环,在循环体中带有一个“DoEvents”。每个事件处理程序可以暂停几秒钟,同时允许刷新完成。它甚至可以像在每个处理程序的开始处包含一个“DoEvents”一样简单。你将需要某种kludge,因为Excel并不是专为多线程而设计的。另外 - 我不记得现在是什么,我曾经遇到过连续需要两个“DoEvents”的情况。作为一个实验开始2 @ –