【发布时间】:2018-06-08 14:22:49
【问题描述】:
设置:
- Windows 7(工作中)
- Windows 10(在家)
- Excel 2016(工作中构建 4627)
- Excel 2016(在家构建 8730)
- Power Query 设置为导入、附加和转换 Excel 文件文件夹。此步骤有效。
使用任何技术等待 Power Query 完成刷新后,如下所示的“我尝试过的事情:”部分所述,可以显示一个消息框,并且可以在 Power Query 表之前执行任何其他代码根据查询和连接窗格中显示的刷新指示器(微调器?)图标完成更新。
上述语句的例外是 Application 类的 OnTime 方法,如下面的“代码”部分所示,它似乎不会中断电源查询刷新的轮询。问题是它使用硬编码的时间量来暂停 VBA 代码,这并不总是有效,因为被查询的数据的大小、数量和持续时间会随着时间而改变。
我试过了:
- 我已阅读所有声明使用
DoEvents、BackgrgoundQuery = False和CalculateUntilAsyncQueriesDone方法和属性的 StackOverflow(和其他网站资源)。 - 我尝试按照此链接的建议为Create Before/After Query Update Events 创建一个类(以下代码示例中未显示)。
- 我尝试使用 Do Until/While 循环和 QueryTable 方法的 .Refreshing = True/False 属性来等待刷新完成。
- 我尝试将 Excel 菜单(菜单栏 --> 数据 --> 连接 --> 属性)中的 BackgroundQuery 属性设置为 False,如此处“subro”所建议的:Wait until ActiveWorkbook.RefreshAll finishes - VBA,此处带有菜单图像:
代码:
Private Sub sht_sub_Refresh_AllConnections_dev()
'Name: sht_sub_Refresh_AllConnections_dev
'Purpose: An attempt at using VBA to wait for Queries to finish updating before displaying a message.
'Description: Waits for a hard coded period of time before dislpaying the message box.
'State: WIP.
'Dev: Needs a way to look at the connection stream to somehow detect when its finished.
'DECLARATIONS:
'------------'
Dim procName As String 'Stores this procedure's name.
Dim qTblLst As QueryTables 'A query table collection object.
Dim qTblObj As QueryTable 'A query table object.
Dim conLst As Connections 'A connection collection object.
Dim conObj As WorkbookConnection 'A connection object.
Dim idx As Long 'A loop counter.
'INITIALIZATIONS:
'---------------'
procName = "sht_sub_Refresh_AllConnections_dev" 'Store this procedure's name.
Linit.ini_Setup_Project 'Setup the project if needed.
Set conLst = ThisWorkbook.Connections 'Set the connections list object.
Set conObj = conLst.Item(conLst.Count) 'Set an initial connection object.
idx = 0 'As an exit if the do loop continues without end.
'MAIN CODE BODY:
'--------------'
'Turn off backgroundquery for each connection type.
For Each conObj In conLst 'For each connection object,
With conObj
Select Case .Type 'Check the connection type,
Case 1 'If its an OLEDB connection then,
.OLEDBConnection.BackgroundQuery = False 'Set it's backgroundquery property to false.
Case 2 'If its an ODBC connection the,
.ODBCConnection.BackgroundQuery = False 'Set it's backgroundquery property to false.
End Select
End With
Next conObj
ThisWorkbook.RefreshAll 'Refresh all connections.
'DEV: Using loops, DoEvents and a query name starting with the letters "zzzz" as suggsted here:
'https://social.technet.microsoft.com/Forums/en-US/bc3f7748-8a52-498d-951c-4566b8adf45a/in-excel-2016-power-queries-dont-refresh-in-the-background-anymore?forum=powerquery
'and here:
'https://www.myonlinetraininghub.com/excel-forum/vba-macros/pause-macro-until-power-queries-finished-refreshing
'Attempt to wait until the last connection has finished refreshing.
Do Until Linit.gvTbl_ZZZZZ.QueryTable.Refreshing = True 'Wait until the last table starts refreshing,
idx = idx + 1 'Icrement a loop count,
If idx > 3000 Then Exit Do 'If the loop goes longer then 3000 iterations exit,
Loop 'otherwise continue waiting.
VBA.DoEvents 'Do events before continueing (doens't work).
Do Until Linit.gvTbl_ZZZZZ.QueryTable.Refreshing = False 'Wait until the last table finishes refreshing,
idx = idx + 1 'Icrement a loop count,
If idx > 3000 Then Exit Do 'If the loop goes longer then 3000 iterations exit,
Loop 'otherwise continue waiting.
VBA.DoEvents 'Do events before continueing (doens't work).
'DEV: The following is an attempt to get connections to
' finish refreshing before code continues as suggested here:
'https://stackoverflow.com/questions/22083668/wait-until-activeworkbook-refreshall-finishes-vba
Application.CalculateUntilAsyncQueriesDone 'This is placed here as well as after the refresh.
VBA.DoEvents 'Do events before continueing (doens't work).
Application.EnableEvents = False 'Maybe turning off events helps? (nope...),
Application.ScreenUpdating = False 'This is reset in the procedure called as an argument to the next line:
Application.OnTime DateAdd("s", 3, Now), _
"Lwksh.sht_sub_Msg_RefreshDone" 'The called procedure just displays a message box.
Application.EnableEvents = True 'Restore events,
Application.ScreenUpdating = True 'Restore screen updating.
'MEMORY CLEANUP:
'--------------'
EXIT_CLEAN:
procName = Empty
Set qTblLst = Nothing
Set qTblObj = Nothing
Set conLst = Nothing
Set conObj = Nothing
idx = 0
End Sub
代码注释:
- 代码中以“Linit”开头的任何内容。是一个对象或变量,由代码的“INITIALIZATIONS:”部分中的“Linit.ini_Setup_Project”过程调用在过程之外全局设置。
- 例如,“Linit.gvTbl_ZZZZZ”是一个对象变量,它指向一个空的单行表,该表的名称带有“zzzz”字符,由 Power Query 生成并加载到 Excel 工作表。该代码显示了指向提出使用此类空表的建议的网站的链接。
问题:
- 这是因为 Power Query 没有内置回调让 Excel 知道它已完成更新任何刷新过程而导致失败吗?
- 如果这不是丢失的原因,是否有任何其他方法(此处未描述)可用于在连接尚未完成刷新时以某种方式触发错误,或者在连接未完成刷新时触发错误连接完成了吗? (这里的想法是,如果错误不会阻止查询完成,则此错误可能会被捕获为检测天气或刷新未完成的一种可能方式。
- 有什么方法可以直接使用 VBA 探测连接流以查找连接关闭或完成状态?
- 有没有什么方法可以通过调用 Excel 之外的程序直接访问刷新过程?
- 您能想出其他可以尝试或测试的方法来完成这项工作吗?我会继续自己寻找答案,但经过一整年的搜索,我感觉有点不走运。
【问题讨论】:
-
@Mike:“TLDR”被理解了。包含所有信息是为了完整地描述问题,这为那些愿意略读以从问题中获得所需内容的人提供了清晰的信息。谢谢你的回答。在确保您发布的内容有效或仍然无效后,我会在您的帖子下进一步评论。
-
它很长,但恕我直言,问题清楚地列出了,您尝试、研究和编码的内容,考虑到您的新功能,做得很好!
标签: excel vba refresh powerquery doevents