【问题标题】:VBA For Excel AfterRefresh EventVBA For Excel AfterRefresh 事件
【发布时间】:2013-02-02 22:08:25
【问题描述】:

我正在使用以下 QueryTable 查询。 .Refresh 执行后,VBA 过程结束。查询有效,但我需要在完成后执行代码。

.AfterRefresh 事件似乎是我需要的,但我无法让它执行。

With ActiveSheet.QueryTables.Add(Connection:="URL;" & sUrl, Destination:=ActiveSheet.Range("a1"))

             .RefreshStyle = xlOverwriteCells
             .SaveData = True
             .Refresh
             .AfterRefresh (Success)
End With

这是未执行的 AfterRefresh 子程序。

Sub QueryTable_AfterRefresh(Success As Boolean)

        If Success Then
                 Debug.Print "Success"
        Else
                 Debug.Print "Failed"
        End If
End Sub

查询完成后触发子程序需要什么?我尝试在 .Refresh 之后和 End With 之后调用子例程,但都没有成功。

谢谢。

【问题讨论】:

    标签: excel vba


    【解决方案1】:

    请确保您的QueryTable_AfterRefresh 子不在模块中,而是在工作表/工作簿下,与此处相同:https://stackoverflow.com/a/14646261/1953175 此外,您不需要调用事件,从您的代码中删除 .AfterRefresh (Success) .

    【讨论】:

    • 当我这样做时,查询没有返回任何内容。
    • 在微软的文档中,似乎推荐的方法是将 AfterRefresh sub 放在类模块中。
    【解决方案2】:

    我最近遇到了同样的问题,很难找到一个好的答案。我意识到这个帖子已经过时了,但是对于发布的其他解决方案有一个不错的替代方案。

    您可以利用的一种模式是将 QueryTable 回调事件保存在单独的 类模块 中,而不是嵌入工作表中。这允许更多模块化、可重用的代码。当您的 Excel 工作簿有多个 QueryTable 时,它​​会变得特别有用。

    这是类模块在名为 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
    

    上面要注意的关键是 WithEvents 关键字以及 BeforeRefresh 和 AfterRefresh 的声明/定义。

    下面是利用上面定义的类模块的代码的样子

    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
    

    这种方法的一个警告是,如果异步运行并保持原样,则不会调用 AfterRefresh。这样做的原因是当模块完成执行时对查询表的引用将消失,这很可能在查询完成执行之前完成。为了解决这个问题,您可以通过设置同步运行它

     qt.Refresh False
    

    但是,这不是最好的方法,但如果您不介意在子模块中的任何其他代码运行之前等待查询,这将是可行的。有关 KazJaw 的 Excel VBA - QueryTable AfterRefresh function not being called after Refresh completes 的替代方案,请参阅这篇文章以获得非常好的答案。

    希望这会有所帮助,因为这是将这些事件处理程序嵌入到工作表中的一个很好的替代方法

    【讨论】:

      【解决方案3】:

      可以在here 找到一个 github 存储库,该存储库演示了实现此工作所需的最少代码。

      正如其他答案中提到的,确保您赶上活动的关键因素是:

      1. 在文件顶部(我选择ThisWorkbook 文件)在任何子例程/方法的外部声明事件处理类模块类型的全局变量。 p>

      2. 添加一个Workbook_Open 事件处理程序并在那里实例化该变量,以便它立即可用并且将保留在范围内(因为它是全局的)。

      3. 此时,或在您有感兴趣的 QueryTable 的任何下游点,将该 QueryTable 传递给全局实例以连接其事件。

      (当有人向我指出这个方向作为this question的答案时,我自己尝试了几次才弄清楚这一点。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-24
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        • 2020-05-09
        相关资源
        最近更新 更多