如何等待Power Query刷新完成?我用"BackgroundQuery = False"尝试了"DoEvents",而且更多,没有任何效果

neu*_*lly 8 excel vba refresh doevents powerquery

建立:

  • Windows 7(在工作中)
  • Windows 10(在家)
  • Excel 2016(在工作中构建4627)
  • Excel 2016(在家建8730)
  • Power Query设置为导入,追加和转换Excel文件的文件夹.这一步有效.

问题描述

使用任何技术的任意组合后,等待Power Query完成刷新,如下面所示的"我尝试过的东西:"部分所述.根据"查询和连接"窗格中显示的刷新指示器(微调器?)图标,可以在Power Query表完成更新之前显示消息框并执行任何其他代码.

上述语句的例外是Application类的"OnTime"方法,如下面的"代码"部分所示,它似乎不会中断电源查询刷新的轮询.但是,此方法的问题在于它使用硬编码的时间来暂停VBA代码,并且这并不总是有效,因为查询的数据的大小,数量和持续时间将随时间而变化.

我尝试过的事情:

  • 我已阅读所有国家使用的"调​​用DoEvents"的StackOverflow上(和其他网站的资源),"BackgrgoundQuery =假",并CalculateUntilAsyncQueriesDone方法和属性.
  • 我已经尝试按照此链接的建议创建一个类来创建查询前/后查询更新事件(下面的代码示例中未显示).
  • 我已经尝试使用Do Until/While循环使用QueryTable方法的.Refreshing = True/False属性来等待刷新完成.
  • 我曾尝试设置在Excel菜单中BackgroundQuery属性(菜单栏- >数据- >连接- >属性)以虚假的"subro"这里的建议:等到ActiveWorkbook.RefreshAll完成- VBA,随着图像菜单在这里:

用于设置BackgroundQuery属性的Excel菜单.

码:

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
Run Code Online (Sandbox Code Playgroud)

代码说明:

  • 代码中的任何内容都以"Linit"开头.是一个对象或变量,它通过代码的"INITIALIZATIONS:"部分中的"Linit.ini_Setup_Project"过程调用在过程外部全局设置.
  • 例如,"Linit.gvTbl_ZZZZZ"是一个对象变量,指向其具有以字符"ZZZZ"明星并且由电源产生的查询,并加载到Excel片一个名称的空一行表.代码显示了网站的链接,其中提出了使用这样的空表的建议.

问题

  1. 这是一个失败的原因,因为Power Query没有内置的回调让Excel知道它已经完成了更新任何刷新过程?
  2. 如果这不是一个丢失的原因,是否有任何其他方法(此处未描述)可用于在连接尚未完成刷新时以某种方式触发错误,或在连接完成时触发错误?(这里的想法是,如果错误不能阻止查询完成,则此错误可能被捕获为检测天气的可能方式或不刷新已完成).
  3. 有没有办法直接使用VBA探测连接流来查找连接关闭或完成状态?
  4. 有没有办法通过调用用C#或Python等其他语言编写的Excel之外的程序来直接访问刷新过程?
  5. 你能想到其他任何可能尝试或测试过的东西吗?我会继续自己寻找答案,但经过整整一年的搜索,我感觉有些运气不好.

感谢您抽出时间和关注此问题.如果我忘记包含任何信息或者可能需要重新编写某些内容以使此问题更加清晰,请在评论中告诉我.

Mik*_*ney -1

我正在调用 ThisWorkbook.Connections.Ranges(1).ListObject.QueryTable 上的 .Refresh 方法,并且使用 BackgroundQuery:=False。它看起来相当可靠 - 到目前为止,我的宏可能已调用该方法超过 10,000 次,并且错误/冻结率非常低。

据我了解,当 PQ 在 Excel 2016 的对象模型中正确公开时,所有这些 DoEvents 解决方法等都变得过时。

这是一个粗略的代码示例:

Dim cn As WorkbookConnection
For Each cn In ThisWorkbook.Connections
    cn.Ranges(1).ListObject.QueryTable.Refresh BackgroundQuery:=False
Next cn
Run Code Online (Sandbox Code Playgroud)

在 For 循环内,您可以检查 cn.Name 来控制单个查询的执行。名称属性位于工作簿连接名称之后,例如“查询 - ”和 PQ 查询名称。