2015-10-26 724 views
1

我遇到競爭條件問題,我有兩個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)

+0

也許每個'AfterRefresh'事件處理程序可以以'Activeworkbook.RefreshAll'結尾,後面跟着'DoEvents',也許有一些切換布爾公共變量來阻止回聲事件。 –

+0

@JohnColeman,但用​​戶已經點擊了內置的全部刷新按鈕,所以如果我爲每個'AfterRefresh'添加'Activeworkbook.RefreshAll'並不意味着它實質上是刷新兩次? 其實,在第二個想法,因爲它是在'AfterRefresh'內,它會觸發無限循環刷新?因爲'AfterRefresh'會觸發另一次刷新,這會再次觸發'AfterRefresh' – Antony

+0

現在我可以更清楚地看到問題了。也許在每個事件處理程序的開始處包含一個定時器循環,在循環體中帶有一個「DoEvents」。每個事件處理程序可以暫停幾秒鐘,同時允許刷新完成。它甚至可以像在每個處理程序的開始處包含一個「DoEvents」一樣簡單。你將需要某種kludge,因爲Excel並不是專爲多線程而設計的。另外 - 我不記得現在是什麼,我曾經遇到過連續需要兩個「DoEvents」的情況。作爲一個實驗開始2 @ –

回答

0

如果明確VBA觸發Activeworkbook.RefreshAll然後之前DoEvents代碼後DoEvents的作品,你想要在事件中運行時,處理程序應覆蓋由Ctrl+Alt+F5觸發刷新的情況。因此,開始每個事件處理程序的行DoEvents

0

變化查詢不允許背景刷新,他們不會放棄控制權,直到刷新

Location of Background refresh

+0

這是可以從Connection屬性UI完成的東西嗎?或者這隻在VBA中完成?因爲如果它在代碼中,我不知道是否需要投資邏輯來檢查它是否已設置爲False。儘管如此,DoEvents看起來還是可以做到的,但我也會嘗試一下。 – Antony

+0

添加了哪裏可以找到背景刷新選項的圖片 – SeanC

+0

謝謝肖恩。我明白了爲什麼你有這個選擇,但我不這樣做,因爲我的外部資源只是兩個不斷更新的CSV文件,而不是SQL連接。 – Antony