最近、この同じ問題に出くわしましたが、良い答えを見つけるのは非常に困難でした. このスレッドが古いことは承知していますが、投稿された他のソリューションに代わる適切な方法があります。
使用できる 1 つのパターンは、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
このアプローチの 1 つの注意点は、これを非同期で実行してそのままにしておくと、AfterRefresh が呼び出されないことです。これは、モジュールの実行が終了すると、クエリ テーブルへの参照が消えてしまうためです。これは、クエリの実行が終了する前に終了する可能性があります。これを回避するには、設定して同期的に実行できます
qt.Refresh False
ただし、これは最善の方法ではありませんが、サブ モジュール内の他のコードが実行される前にクエリを待機することを気にしない場合は機能します。このExcel VBA の代替案に関する本当に良い回答については、この投稿を参照してください - KazJaw によって更新が完了した後に QueryTable AfterRefresh 関数が呼び出されません。
これは、ワークシートに埋め込まれたこれらのイベント ハンドラーを記述するための優れた代替手段であるため、これが役立つことを願っています。