Tôi đang phát triển ứng dụng Excel (2010+) sử dụng VBA và đã gặp sự cố khi chức năng sự kiện AfterRefresh không được gọi khi truy vấn kết thúc thực thi.Excel VBA - chức năng QueryTable AfterRefresh không được gọi sau khi Refresh hoàn thành
Tôi chưa thể tìm thấy nhiều tài nguyên hoặc tài liệu phong nha để biết cách kích hoạt chức năng sự kiện này trong Mô-đun lớp học. Tôi quyết định sử dụng tuyến đường thiết kế mô-đun lớp thay vì đặt trình xử lý sự kiện trong trang tính sau khi nhận được câu trả lời cho câu hỏi trước đó về QueryTables (được tìm thấy tại đây Excel VBA AfterRefresh).
Đây là mã cho Mô-đun lớp tôi gọi 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
Đây là một ảnh chụp nhanh của mã này tạo ra một thể hiện của lớp này, tìm thấy một QueryTable có liên quan, sau đó gọi 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
Ngoài ra, đây là ảnh chụp màn hình Cấu trúc mô-đun http://imgur.com/8fUcfLV
Suy nghĩ đầu tiên của tôi về vấn đề có thể là gì khi truy cập QueryTable theo giá trị. Tôi không phải là nhà phát triển VBA có kinh nghiệm nhất, nhưng tôi đã lý luận điều này sẽ tạo một bản sao và gọi sự kiện trên một bảng không liên quan. Tuy nhiên, đây không phải là trường hợp và đi qua tham chiếu cũng không khắc phục được vấn đề.
Ngoài ra truy vấn được xác nhận để chạy thành công khi dữ liệu được hiển thị chính xác và đang được làm mới.
EDIT tôi đã thêm chức năng sự kiện BeforeRefresh để CQtEvents lớp Module và xác nhận chức năng này được gọi là một lần Refresh được gọi
Private Sub mQryTble_BeforeRefresh(Cancel As Boolean)
MsgBox "Start of BeforeRefresh"
End Sub
Làm thế nào tôi có thể thay đổi mã này được QueryTable tôi từ RefreshDataQuery của QTableModule() Thường trình con để có hàm AfterRefresh được gọi khi truy vấn được chạy thành công?
nhưng không có 'MsgBox' trong sự kiện' AfterRefresh' của bạn Sub. Vì vậy, làm thế nào để bạn biết nếu nó đã hoàn thành/làm mới? Tôi không thể nhìn thấy mã đang kiểm tra trạng thái của sự kiện đó. Bạn có thể thêm 'MsgBox' vào sự kiện để kiểm tra xem (nếu) nó hoạt động như thế nào. –
@KazJaw Tôi đặt một MsgBox trong chức năng sự kiện và xác nhận nó không được gọi. Ngoài ra, một cách khác tôi có thể xác nhận là xem truy vấn QueryTable để xác minh rằng bản gốc đã được khôi phục, đó là những gì tôi đã làm thay vì sử dụng một MsgBox. –
giữ hộp thông báo trong 'sự kiện AfterRefresh' và gọi lại làm mới trong chính bạn theo cách sau:' qt.Refresh false'. Bạn có nhận được MsgBox ngay bây giờ không? –