Excel VBA - 在Refresh完成后未调用QueryTable AfterRefresh函数

Pau*_*ton 5 excel vba excel-vba

我正在使用VBA开发Excel(2010+)应用程序,并遇到一个问题,一旦查询完成执行,就不会调用AfterRefresh事件函数.

我无法找到许多有关如何在类模块中触发此事件功能的合适资源或文档.我决定使用类模块设计路线,而不是在收到有关QueryTables的早期问题(在此处找到Excel VBA AfterRefresh)的响应后,将事件处理程序放在工作表中.

这是我的类模块的代码,称为CQtEvents

Option Explicit

Private WithEvents mQryTble As Excel.QueryTable
Private msOldSql As String

' Properties
Public Property Set QryTble(ByVal QryTable As QueryTable): Set mQryTble = QryTable:
End Property
Public Property Get QryTble() As QueryTable: Set QryTble = mQryTble:
End Property
Public Property Let OldSql(ByVal sOldSql As String): msOldSql = sOldSql:
End Property
Public Property Get OldSql() As String: OldSql = msOldSql:
End Property

Private Sub Class_Initialize()
    MsgBox "CQtEvents init"
End Sub

' Resets the query sql to the original unmodified sql statement
' This method is invoked when the Refresh thread finishes executing
Private Sub mQryTble_AfterRefresh(ByVal Success As Boolean)
    ' Problem is here
    ' This function is never called :( Even if the query successfully runs
    Me.QryTble.CommandText = Me.OldSql

End Sub
Run Code Online (Sandbox Code Playgroud)

下面是创建此类实例的代码的快照,查找相关的QueryTable,然后调用Refresh

Option Explicit

Sub RefreshDataQuery()
'Dependencies: Microsoft Scripting Runtime (Tools->References) for Dictionary (HashTable) object

'From MGLOBALS
cacheSheetName = "Cache"
Set cacheSheet = Worksheets(cacheSheetName)

Dim querySheet As Worksheet
Dim interface As Worksheet
Dim classQtEvents As CQtEvents

Set querySheet = Worksheets("QTable")
Set interface = Worksheets("Interface")
Set classQtEvents = New CQtEvents

Dim qt As QueryTable
Dim qtDict As New Scripting.Dictionary

Set qtDict = UtilFunctions.CollectAllQueryTablesToDict
Set qt = qtDict.Item("Query from fred2")

''' Building SQL Query String '''
Dim sqlQueryString As String
sqlQueryString = qt.CommandText
Set classQtEvents.QryTble = qt
classQtEvents.OldSql = sqlQueryString ' Cache the original query string


QueryBuilder.BuildSQLQueryStringFromInterface interface, sqlQueryString

' Test message
MsgBox sqlQueryString
qt.CommandText = sqlQueryString

If Not qt Is Nothing Then
    qt.Refresh
Else
    ' ... Error handling code here... 
End If


''' CLEAN UP '''

' Free the dictionary
Set qtDict = Nothing

End Sub
Run Code Online (Sandbox Code Playgroud)

此处还有模块结构的屏幕截图http://imgur.com/8fUcfLV

我首先想到的可能是问题是通过值传递QueryTable.我不是最有经验的VBA开发人员,但我推断这会创建一个副本并在不相关的表上调用该事件.但是,情况并非如此,并且通过Reference传递也没有解决问题.

此外,当数据正确显示并刷新时,确认查询成功运行.

编辑 我将BeforeRefresh事件函数添加到CQtEvents类Module并确认调用Refresh后调用此函数

Private Sub mQryTble_BeforeRefresh(Cancel As Boolean)
    MsgBox "Start of BeforeRefresh"
End Sub
Run Code Online (Sandbox Code Playgroud)

我如何改变这段代码从QTableModule的RefreshDataQuery()Sub例程获取我的QueryTable,以便在成功运行查询时调用AfterRefresh函数?

Kaz*_*wor 4

如何捕获AfterRefresh eventQueryTable的?

QueryTable说明:在您的情况下,在事件被触发之前,您在进行清洁或程序结束时将其设置为空,从而丢失了您的参考。

一般解决方案:您必须确保您的代码仍在运行和/或您需要保留对QueryTable.

第一个解决方案。调用时QT.Refresh method设置参数false如下:

qt.Refresh false 
Run Code Online (Sandbox Code Playgroud)

这将停止进一步的代码执行,直到qt刷新为止。但我不认为这个解决方案是最好的。

第二个解决方案。公开您的classQtEvents variable信息,RefreshDataQuery sub完成后使用其他代码检查状态。

  1. 添加CQtEvents class module以下公共变量:

    Public Refreshed As Boolean
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在你BeforeRefresh event添加这个:

    Refreshed  = False
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在你AfterRefresh event添加这行代码:

    Refreshed = True
    
    Run Code Online (Sandbox Code Playgroud)
  4. 公开您的classQtEvents variable声明。把这个放在前面Sub RefreshDataQuery()

    Public classQtEvents as CQtEvents
    
    Run Code Online (Sandbox Code Playgroud)

但从你的子程序中删除适当的声明。

现在,即使您的子程序已完成,您也可以通过检查来检查刷新状态.Refreshed property。您可以在立即或其他子中执行此操作。这应该适用于立即:

Debug.Print classQtEvents.Refreshed
Run Code Online (Sandbox Code Playgroud)

第三个解决方案。(与第一个有点相似)按照第二个解决方案中的步骤 1 到步骤 3 进行操作。调用后,qt.Refresh method您可以添加此循环,该循环将停止进一步的代码执行,直到qt刷新:

'your code
If Not qt Is Nothing Then
    qt.Refresh
Else
    ' ... Error handling code here... 
End If
'checking
Do Until classQtEvents.Refreshed
    DoEvents
Loop
Run Code Online (Sandbox Code Playgroud)

最后一句话。我希望我没有和 混qt variable在一起classQtEvents variable。我没有使用您的变量尝试和测试任何解决方案,而是参考我使用的代码编写了上述所有内容。