I am running into a race condition issue where I have two QueryTables, each is hooked with its own AfterRefresh event. Each AfterRefresh event does some copy'n'pasting as well as doing some calculations.
Now, when the user click Refresh All (Ctrl+Alt+F5)
in Excel, I would love to have each AfterRefresh handler to execute, but ONLY after all QueryTable refreshes are entirely completed.
I did a search on StackOverFlow, and someone suggested
Activeworkbook.RefreshAll
DoEvents
However, that's assuming that we are programmatically triggering the RereshAll. In my case, Refresh All is done by the built-in Refresh All (Ctrl+Alt+F5)
button within Excel. Thus, I don't see where I can insert DoEvents
in my case (unless I create my own Refresh All button, but I would like to avoid doing so).
I tried to search for "Excel VBA mutex", but I did not find anything in particular. So how do I make sure that all the refreshes are done, before each AfterRefresh handler takes place?
Thanks for reading!
Update: To help out with debugging.. here are my VBA codes.
I have a module named 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
I also have a Class module named 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
Because of the race condition, only one AfterRefresh handler succeeds in copy'n'pasting.. the other one doesn't work until I click Refresh All button (Ctrl+Alt+F5)
again.