我正在尝试将多维数据集函数的范围级刷新构建到一个基于多维数据集公式的大型工作簿中,因为当整个工作簿被刷新(小时和小时)时,这些函数的批处理在可用的多维数据集上总是执行得非常糟糕等待)。
我尝试使用的代码非常简单:
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 触发相同的东西?
最佳答案
这不起作用的原因是,无论出于何种原因,触发异步连接以使用立方体值公式获取数据的后计算事件在 VBA 运行时无法触发。这包括调用 DoEvents 的 VBA(因此上面的代码不起作用)。
但是,事件已安排并触发 - 一次,无论调用了多少次 Calculate - 一旦 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 在整个 Excel session 期间有效,除非被取消 这意味着如果您让 Excel 运行超过 24 小时,预计宏会再次触发。我被告知,为了达到效果,这甚至可能打开关闭的工作簿,所以请注意。不过,当 Excel 关闭时,OnTime 事件将失效。
- 这意味着如果您通过单击停止、在 VBA 中其他地方出现错误或通过其他方式暂停代码,您将无法知道当前安排了哪些 OnTime 事件(如果有人知道如何找到它,我很想知道)
但是,考虑到这些附带条件,这种方法将允许触发正确的事件以启动多维数据集功能。当然,检测它们何时完成是完全不同的事情。
关于vba - 从 VBA 触发计算时,#GETTING_DATA 消息永远不会解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22223354/