2

System.Net.Sockets.NetworkStream.BeginReadの完了時に非同期的に呼び出されるメソッドがあります。

 skDelegate = New AsyncCallback(AddressOf skDataReceived)
 skStream.BeginRead(skBuffer, 0, 100000, skDelegate, New Object)

そのコールバック メソッドでは、UI スレッドと対話する必要があります。

Sub skDataReceived(ByVal result As IAsyncResult)
    CType(My.Application.OpenForms.Item("frmMain"), frmMain).refreshStats(d1, d2)
End Sub

これにより、メソッドの完了後に例外が発生します。(End Sub実行時)

元に戻す操作で、対応するセット操作で適用されたものとは異なるコンテキストが検出されました。考えられる原因は、コンテキストがスレッドで設定され、元に戻されていない (元に戻されていない) ことです。

では、コールバック メソッドから UI スレッドを操作するにはどうすればよいでしょうか。私は何を間違っていますか?

4

4 に答える 4

2

UI スレッドで実行するメッセージ (デリゲート) をキューに入れるには、frmMain オブジェクトで Invoke または BeginInvoke を使用する必要があります。

C# で行う方法を次に示します。

frmMain.Invoke(() => frmMain.refreshStats(d1, d2));

Invoke の種類とその用途のリストも確認してください。

于 2009-11-15T06:22:45.333 に答える
1

トラビスは正しいです。Windows フォーム アプリケーションはシングル スレッドであり、他のスレッドから UI にアクセスすることはできません。BeginInvoke を使用して UI スレッドへの呼び出しをマーシャリングする必要があります。

参照: http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx

于 2009-11-15T06:27:52.660 に答える
1

UI スレッドで frmMain.refreshStats メソッドを呼び出す必要があります。もちろん、Control.InvokeRequired プロパティと Control.Invoke ( MSDN ドキュメント) を使用してこれを行う方法は多数あります。

「EndAsync」メソッドでメソッド呼び出し UI スレッド セーフにするか、refreshStats メソッドでスレッド セーフをチェックする (Control.InvokeRequired を使用) ことができます。

EndAsync UI のスレッドセーフは次のようになります。

Public Delegate Sub Method(Of T1, T2)(ByVal arg1 As T1, ByVal arg2 As T2)

Sub skDataReceived(ByVal result As IAsyncResult)
    Dim frmMain As Form = CType(My.Application.OpenForms.Item("frmMain"), frmMain)
    Dim d As Method(Of Object, Object)
'create a generic delegate pointing to the refreshStats method
    d = New Method(Of Object, Object)(AddressOf frmMain.refreshStats)
'invoke the delegate under the UI thread
    frmMain.Invoke(d, New Object() {d1, d2})
End Sub

または、refreshStats メソッドをチェックして、UI スレッドの下でそれ自体を呼び出す必要があるかどうかを確認できます。

Public Delegate Sub Method(Of T1, T2)(ByVal arg1 As T1, ByVal arg2 As T2)

Sub refreshStats(ByVal d1 As Object, ByVal d2 As Object)
'check to see if current thread is the UI thread
    If (Me.InvokeRequired = True) Then
        Dim d As Method(Of Object, Object)
'create a delegate pointing to itself
        d = New Method(Of Object, Object)(AddressOf Me.refreshStats)
'then invoke itself under the UI thread
        Me.Invoke(d, New Object() {d1, d2})
    Else
        'actual code that requires UI thread safety goes here
    End If
End Sub
于 2009-11-16T06:39:15.790 に答える
0

UIスレッドでフォームからプロパティを操作したり、読み取ったりするたびに発生する、繰り返し発生するInvalidContextExceptionエラーの解決策(実際には回避策!)を見つけました。

Async コールバック メソッドから UI スレッドを操作する前後に、実行コンテキストをバックアップおよび復元する必要がありました。その後、例外は現れたときと同じように不可解に消え、デリゲートや呼び出しを使用することなく、Async コールバックから同期的に、プロパティの読み取り/書き込み、メソッドの呼び出し、基本的に UI スレッドで好きなことを行うことができます!

この例外は、実際には .NET フレームワーク自体の低レベルのバグです。Microsoft Connect バグ レポートを参照してください。ただし、機能的な回避策が記載されていないことに注意してください。

回避策: (製品コード)

Sub skDataReceived(ByVal result As IAsyncResult)

    // backup the context here
    Dim syncContext As SynchronizationContext = AsyncOperationManager.SynchronizationContext

    // interact with the UI thread
    CType(My.Application.OpenForms.Item("frmMain"), frmMain).refreshStats(d1, d2)

    // restore context.
    AsyncOperationManager.SynchronizationContext = syncContext
End Sub
于 2009-11-15T07:42:38.487 に答える