2014-03-06 43 views
0

我試圖建立範圍級別刷新的多維數據集功能成一個大的立方基於公式的工作簿,因爲這些功能的批量生成總是可怕地執行多維數據集可用當整個工作簿被刷新時(等待幾小時和幾小時)。#GETTING_DATA消息永遠不會解決當從VBA觸發計算

我試圖使用的代碼非常簡單:

Public Sub RefreshRange() 
    Dim rngTarget As Excel.Range 
    Dim lngRescue As Long 
    Dim blnCalcCheck As Boolean 

    Set rngTarget = Selection 
    Do 
     rngTarget.Dirty 
     rngTarget.Calculate 
     DoEvents    '' Used reluctantly in case VBA blocks the event that 
           '' causes a recalc 
     blnCalcCheck = blnCalcCheck Or ThisWorkbook.Connections("MyConnection").OLEDBConnection.Refreshing 
     lngrescue = lngRescue + 1 
     Sleep 200    '' API sleep function. Also tried Application.Wait. 
     If lngRescue >= 200 Then Debug.Assert False 

    Loop Until Not fblnIsGettingData(rngTarget) '' This function doesn't do much that 
               '' could break things. Just evaluates 
               '' a formula for rngTarget that checks 
               '' if any of the cells read 
               '' #GETTING_DATA 

End Sub 

這是行不通的。公式計算,解析爲#GETTING_DATA,但連接永遠不會開始收集數據的過程進入它們。這只是開始,以不同程度的可靠性,如果我

  • 手動重新計算工作表(Shift-F9)。這大概有50%的時間。
  • 手動重新計算整個工作簿。這在大約80%的時間內工作。
  • 將計算模式設置爲自動。這總是有效(到目前爲止),但始終是工作簿級別的。

它也可能開始,如果我叫Application.CalculateUntilAsyncQueriesDone工作,但我不知道,因爲這顯然是一個工作簿級的功能和更多的點,一直似乎崩潰我的工作簿(我猜是因爲我在經常使用的名稱中使用UDF,但不確定)。

有沒有人有任何想法如何手動啓動它是啓動整個「運行後臺查詢」消息的範圍?或者,我怎樣才能看到Excel.Exe流程,以便找出並可能通過API激發相同的事情?

回答

0

這不起作用的原因是因爲,無論什麼原因,在VBA運行時,觸發異步連接去獲取數據和Cube值公式的後期計算事件無法觸發。包括調用DoEvents的VBA(因此上面的代碼不起作用)。

但是,一旦VBA完成所做的任何事情,該事件就會被計劃並觸發一次,無論計算被調用了多少次。這使得使用定時器進行編碼變得複雜但並非不可能(爲了能夠輕鬆地對所有東西進行分類,我最終選擇了Application.OnTime),但API SetTimer也可能起作用。解決此問題的一種非常簡單的方法是(可能的這裏的錯誤,因爲我真的不習慣使用靜態):

Public Static Sub DoCalcEvery(Optional strInterval As String = vbNulLString, Optional wksTarget As Excel.Worksheet, blnContinue As Boolean = True) 
    Dim strInterval_Inner As String 
    Dim wksTarget_Inner as Excel.Worksheet 
    Dim blnContinue_Inner As Boolean 
    Dim lngCalcCount As Long 
    Dim datNewCalcTime As Date 
    Dim datPreviousCalcTime As Date 

    '' Update static values if any new arguments provided 
    '' Stopping is a little tricky too - hence blnContinue 
    If strInterval <> vbNullString Then strInterval_Inner = strInterval 
    If Not wksTarget Is Nothing Then Set wksTarget_Inner = wksTarget 
    If lngCalcCount = 0 Then 
     blnContinue_Inner = blnContinue 
    ElseIf blnContinue <> True Then 
     blnContinue_Inner = False 
    End If 

    '' Clear out any previous OnTime instances 
    '' This frequently (always?) errors, but looks like it is usually wrapped in 
    '' On Error elsewhere, so guessing in THIS specific case, the error is safely 
    '' ignored. 
    On Error Resume Next 
    Application.OnTime datPreviousCalcTime, "DoCalcEvery", , False 
    On Error Goto 0 

    wksTarget.Calculate 
    lngCalcCount = lngCalcCount + 1 
    If blnContinue_Inner Then 
     datNewCalcTime = Now + CDat(strInterval) 
     Application.OnTime datNewCalcTime, "DoCalcEvery" 
     datPreviousCalcTime = datNewCalcTime 
    Else 
     Debug.Print "Calculation complete. " & lngCalcCount & " iterations before stopped." 
    End If 
End Sub 

這應該工作,並允許您DoCalcEvery在任意時間被稱爲停止計算然而,如果使用這種方法也有一些需要注意的事項如果您不熟悉OnTime:

  • OnTime適用於整個th是Excel會話,除非取消這意味着如果您將Excel運行超過24小時,則預計該宏將再次啓動。我很抱歉說,爲了達到這個效果,甚至可能會打開關閉的工作簿,所以要提醒一下。當Excel關閉時OnTime事件失效。
  • 這意味着如果您通過單擊停止,VBA中其他位置的錯誤或其他方式來停止代碼,則無法知道當前安排了哪些OnTime事件(如果有人確實知道如何找到它,我很想知道)

但是,考慮到這些附帶條件,這種方法將允許觸發正確的事件來啓動立方函數。當然,檢測它們何時完成是完全不同的一堆魚。

相關問題