等到Excel RefreshAll(Ctrl + Alt + F5)结束 - VBA

时间:2015-10-26 23:45:20

标签: excel vba excel-vba mutex race-condition

我遇到了一个竞争条件问题,我有两个QueryTables,每个QueryTables都有自己的AfterRefresh事件。每个AfterRefresh事件都会进行一些copy'n'pasting以及进行一些计算。

现在,当用户单击Excel中的全部刷新(Ctrl+Alt+F5)时,我希望每个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中成功..另一个在我再次单击Refresh All按钮(Ctrl+Alt+F5)之后不起作用。

2 个答案:

答案 0 :(得分:0)

将查询更改为不允许后台刷新,并且在刷新之前不会放弃控制

Location of Background refresh

答案 1 :(得分:0)

如果DoEvents在显式VBA触发器Activeworkbook.RefreshAll后工作,那么之前您希望在事件处理程序中运行的代码应覆盖由DoEvents触发刷新的情况。因此,使用行Ctrl+Alt+F5开始每个事件处理程序。