更新: MainForm のウィンドウ ハンドルの遅延インスタンス化と関係があると思いますが、ここで見られる動作がどのように発生するかを完全に理解することはできませんでした。
アプリケーションは、結果を処理するためのコールバックを提供するサードパーティの COM インターフェイスを介してデータを要求します。コールバックでは、UI を更新する必要がありますが、更新が期待どおりに機能しません。MainForm.DataReady
クロス スレッドで直接呼び出されるか呼び出されると、MainForm の値のコピーが作成されたかのようになりますが、イベント ハンドラーから実行されると、UI の更新は期待どおりに機能します。理由を説明できますか?
(注: MainForm または ClassB で検査されるかどうかAppDomain.CurrentDomain.Id
は常にです。)1
初期コード- MainForm で InvokeRequred /Delegate /Invoke ロジックを使用せずに、ClassB インスタンスから DataReady を呼び出します。アプリケーション UI の変更は期待どおりに機能し、MainFormSomeListControl.EmptyListMsg = "Not Available"
の変更は「定着」しません (あたかも MainForm の別のコピーに適用されたかのように)。
Module AppGlobals
Public WithEvents A As ClassA
End Module
Partial Friend Class MyApplication
Private Sub MyApplication_Startup(ByVal sender As Object,
ByVal e As StartupEventArgs) Handles Me.Startup
A = New ClassA()
End Sub
End Class
Class MainForm
private sub getData
ToggleWait(True)
SomeListControl.Clear()
A.getData() 'Sets up the com object & callback
end sub
Public Sub DataReady()
ToggleWait(False)
' Do something with the data
End Sub
Private Sub ToggleWait(toggle as Boolean)
Application.UseWaitCursor = False
if toggle then
SomeListControl.EmptyListMsg = "Not Available"
else
SomeListControl.EmptyListMsg = "Please Wait"
end if
End Sub
End Class
Class ClassA
public sub getData()
Dim ComObj as New ComObject
Call ComObj.setClient(New ClassB)
End Sub
End Class
Class ClassB
Implements IComObjectClient
sub getdata_callback(results() as Object) handles IComObjectClient.getdata_callback
' Get the results
MainForm.DataReady()
end sub
End Class
InvokeRequred ロジックを DataReady に追加しましたが、引き続き ClassB から直接呼び出されます。InvokeRequired が true になることはありません。アプリケーション UI の変更は期待どおりに機能し、MainFormSomeListControl.EmptyListMsg = "Not Available"
の変更は「固定」されません (MainForm の別のコピーに適用されたかのように)。
Class MainForm
Public Delegate Sub DataReadyDelegate(ByVal toggle As Boolean)
...
Public Sub DataReady()
If InvokeRequired Then
Invoke(New DataReadyDelegate()
Else
ToggleWait(False)
' Do something with the data
End If
End Sub
...
End Class
MainForm.DataReady
ClassB から直接呼び出された例外が発生しました:「ウィンドウ ハンドルが作成されるまで、Invoke または BeginInvoke をコントロールで呼び出すことはできません。」ウィンドウハンドルの作成を強制するまで。次に、以前と同じ動作です。つまり、InvokeRequired が true になることはなく、アプリケーション UI の変更は期待どおりに機能し、MainFormSomeListControl.EmptyListMsg = "Not Available"
の変更は「固定」されません (MainForm の別のコピーに適用されたかのように)。
Class ClassB
Implements IComObjectClient
Public Delegate Sub DataReadDelegate()
sub getdata_callback(results() as Object) handles IComObjectClient.getdata_callback
' Get the results
If Not MainForm.IsHandleCreated Then
' This call forces creation of the control's handle
Dim handle As IntPtr = MainForm.Handle
End If
MainForm.Invoke(New DataReadyDelegate(AddressOf MainForm.DataReady))
end sub
End Class
イベント ハンドラから実行ClassA および ClassB で定義されたカスタム 'データ取得' イベント。ClassA は ClassB.got_data_event をリッスンして ClassA.got_data_event を発生させます。MainForm は ClassA.got_data_event をリッスンし、DataReady() を呼び出して処理します。これは機能します - InvokeRequired が true で、Invoke が実行され、アプリケーション UI と MainForm UI の変更が意図したとおりに機能します。
Class MainForm
Public Delegate Sub DataReadyDelegate()
...
Public Sub DataReady()
If InvokeRequired Then
Invoke(New DataReadyDelegate()
Else
ToggleWait(False)
' Do something with the data
End If
End Sub
Public Sub _GotData_HandleEvent(ByVal resultMessage As String)
DataReady()
End Sub
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles Me.Load
...
ToggleWait(False)
AddHandler A.GotData, AddressOf _GotData_HandleEvent
...
End Sub
...
End Class