Zajmuję się tworzeniem aplikacji Excel (2010+) przy użyciu języka VBA i napotkam problem, w którym funkcja zdarzenia AfterRefresh nie jest wywoływana po zakończeniu wykonywania kwerendy.Excel VBA - funkcja QueryTable AfterRefresh nie jest wywoływana po zakończeniu odświeżania
Nie byłem w stanie znaleźć wielu przyzwoitych zasobów ani dokumentacji, jak uruchomić tę funkcję zdarzenia w module klasy. Zdecydowałem się użyć trasy projektowania modułu klasy zamiast umieszczania procedur obsługi zdarzeń w arkuszu po otrzymaniu odpowiedzi na wcześniejsze pytanie dotyczące QueryTables (tutaj: Excel VBA AfterRefresh).
Oto kod dla mojego moduł klasy zwane 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
Oto szybki zrzut kodzie tworzy instancję tej klasy, znajdzie odpowiednie QueryTable, następnie wywołuje Odśwież
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
Tutaj znajduje się zrzut ekranu struktury modułu http://imgur.com/8fUcfLV
Moja pierwsza myśl na temat tego, co może być problemem, to przekazanie QueryTable według wartości. Nie jestem najbardziej doświadczonym programistą VBA, ale rozumowałem, że stworzy to kopię i wywoła zdarzenie na niepowiązanym ze sobą stole. Jednak tak się nie stało i przekazanie przez Reference nie rozwiązało problemu.
Również zapytanie jest poprawnie uruchamiane, ponieważ dane są poprawnie wyświetlane i odświeżane.
EDIT dodałem funkcję zdarzeń BeforeRefresh do modułu klasy CQtEvents i potwierdzone ta funkcja jest wywoływana raz Refresh nazywa
Private Sub mQryTble_BeforeRefresh(Cancel As Boolean)
MsgBox "Start of BeforeRefresh"
End Sub
Jak mogę zmienić ten kod dostać mój QueryTable od tego QTableModule za RefreshDataQuery() Podrzędna procedura wywoływania funkcji AfterRefresh po pomyślnym uruchomieniu zapytania?
ale nie ma 'MsgBox' w twoim zdarzeniu" AfterRefresh ". Skąd wiesz, czy jest gotowy/odświeżony? Nie widzę, żeby kod sprawdzał status tego wydarzenia. Możesz dodać "MsgBox" do zdarzenia, aby sprawdzić, jak działa (jeśli). –
@KazJaw Umieściłem MsgBox w funkcji zdarzenia i potwierdziłem, że nie jest wywoływane. Innym sposobem, który mogę potwierdzić, jest przeglądanie kwerendy QueryTable w celu sprawdzenia, czy oryginał został przywrócony, co właśnie robiłem zamiast używać MsgBox. –
zachować okno komunikatu w ramach zdarzenia "AfterRefresh" i wywołać odświeżenie w głównej podsieci w ten sposób: 'qt.Refresh false'. Czy otrzymujesz teraz MsgBox? –