I am using the following QueryTable Inquiry. After the .Refresh
executes the VBA procedure ends. The inquiry works but I need to execute code after it complete
Please make sure your QueryTable_AfterRefresh
sub is placed NOT in the module, but under Sheet / Workbook, the same way as here: https://stackoverflow.com/a/14646261/1953175 Moreover, you do not need to call event, remove .AfterRefresh (Success)
from your code.
I ran across this same issue recently and it was very difficult to find a good answer. I realize this thread is old, but there is a decent alternative to the other solution posted.
One pattern you can utilize is keeping the QueryTable callback events in a separate Class Module instead of embedded within a worksheet. This allows for more modular, reusable code. It becomes especially useful when your Excel Workbook has multiple QueryTables.
Here is what the class module might look like in a class module called CQtEvents
Option Explicit
Private WithEvents mQryTble As Excel.QueryTable
' Add variables you may want to cache here such at the query or connection settings
' 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
' Add other potential properties here
Private Sub Class_Initialize()
' Constructor
MsgBox "CQtEvents init"
End Sub
Private Sub mQryTble_BeforeRefresh(ByVal Cancel as Boolean)
'Insert logic you want to run before a refresh
End Sub
Private Sub mQryTble_AfterRefresh(ByVal Success As Boolean)
'Insert logic you want to run after a refresh
End Sub
The key thing to note above is the WithEvents keyword and the declarations/definitions for BeforeRefresh and AfterRefresh.
Below is what the code might look like to leverage the Class Module defined above
Option Explicit
Sub RefreshDataQuery()
'Dependencies: Microsoft Scripting Runtime (Tools->References) for Dictionary (HashTable) object
Dim querySheet As Worksheet
Dim classQtEvents As CQtEvents
Set querySheet = Worksheets("QTable")
Set interface = Worksheets("Interface")
Set classQtEvents = New CQtEvents ' Instantiate the Class
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 '''
qt.CommandText = "Select * From someTable"
If Not qt Is Nothing Then
qt.Refresh False ' See link at bottom of post for alternatives to this
Else
' ... Error handling code here...
End If
''' CLEAN UP '''
' Free the dictionary
Set qtDict = Nothing
End Sub
The one caveat with this approach is that the AfterRefresh will not be called if this is run asynchronously and left as is. The reason for this is the reference to the query table will disappear when the module finishes executing, which is likely to finish before the query finishes executing. To get around this, you can run it synchronously by setting
qt.Refresh False
However, this is not the best approach but will work if you don't mind waiting on the query before any other code in the Sub Module runs. See this post for a really good answer on alternatives to this Excel VBA - QueryTable AfterRefresh function not being called after Refresh completes by KazJaw.
Hope this helps as this is a good alternative to writing these event handlers embedded in a worksheet
A github repo that demonstrates the minimum code needed to get this working can be found here.
As mentioned in the other answers, the key factors to ensuring you catch the event are:
Declare a global variable of your event-handling class module's type outside of any subroutines/methods, at the top of a file (I chose the ThisWorkbook
file).
Add a Workbook_Open
event handler and instantiate that variable there, so that it is available immediately and will remain in scope (since it's global).
At that point, or at any downstream point when you have a QueryTable you're interested in, pass that QueryTable to the global instance to wire up its events.
(It took me a couple tries to figure this out myself, when someone pointed me in this direction as an answer to this question.)