VBA For Excel AfterRefresh Event

后端 未结 3 1870
太阳男子
太阳男子 2021-01-14 08:19

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

相关标签:
3条回答
  • 2021-01-14 08:35

    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.

    0 讨论(0)
  • 2021-01-14 08:44

    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

    0 讨论(0)
  • 2021-01-14 08:49

    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:

    1. 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).

    2. 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).

    3. 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.)

    0 讨论(0)
提交回复
热议问题