Frage

Ich habe eine Methode, die asynchron genannt wird, wenn System.net.sockets.networkStream.BeginRead vervollständigt.

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

Bei dieser Rückrufmethode muss ich mit dem UI -Thread interagieren.

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

Dies führt zu einer Ausnahme nach Abschluss der Methode. (Wenn das Ende sub ausgeführt wird)

Der Rückgängigungsbetrieb stieß auf einen Kontext, der sich von dem unterscheidet, was im entsprechenden festgelegten Vorgang angewendet wurde. Die mögliche Ursache ist, dass ein Kontext auf den Thread gesetzt und nicht zurückgekehrt (rückgängig gemacht).

Wie interagiere ich mit dem UI -Thread aus der Callback -Methode? Was mache ich falsch?

War es hilfreich?

Lösung

Sie müssen auf dem frminain -Objekt auf Invoke oder Startinvoke beginnen, um eine Nachricht (einen Delegierten) auf den UI -Thread auszuführen.

So würde ich es in C#machen.

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

Überprüfen Sie auch das Liste der aufgerufenen Typen und deren Verwendungen.

Andere Tipps

Travis ist richtig. Windows Forms Application sind ein einzelnes Thread. Sie können von keinem anderen Thread auf die Benutzeroberfläche zugreifen. Sie müssen den Anruf zum UI -Thread mit BeginnInvoke Marshall marken.

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

Sie müssen den UI -Thread auf die Methode frmmain.refreshstats aufrufen lassen. Es gibt viele Möglichkeiten, dies mithilfe der Steuerung zu tun.MSDN -Dokumentation).

Sie können entweder die "Endasync" -Methode haben, um die Methode -Call -UI -Thread sicherzustellen, oder die Aktualisierungsmethode überprüft auf Thread -Sicherheit (mit Control.inVokeRequeured).

Endasync UI-Thread-Safe wäre so etwas:

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

Oder Sie können die Refreshstats -Methode überprüfen lassen, um festzustellen, ob sie sich unter dem UI -Thread aufrufen muss:

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

Ich fand die Lösung (Workaround, eigentlich!) Zu diesem wiederkehrenden InvalidContextexception -Fehler, den ich immer dann bekam, wenn ich eine Eigenschaft aus einem Formular auf dem UI -Thread interagierte oder sogar las.

Ich musste den Ausführungskontext vor und nach der Interaktion mit dem UI -Thread von meiner asynchronen Callback -Methode sichern und wiederherstellen. Dann verschwindet die Ausnahme genauso auf mysteriöse Weise, wie sie erschien, und Sie können Eigenschaften lesen/schreiben, Methoden aufrufen und im Grunde alles tun, was Sie mit dem UI -Thread synchron aus Ihrem asynchronen Rückruf mögen, ohne Delegierte oder Invozes verwenden zu müssen!

Diese Ausnahme ist tatsächlich ein Fehler mit niedrigem Niveau im .NET-Framewok selbst. Siehe das Microsoft Connect -Fehlerbericht, Beachten Sie jedoch, dass sie keine funktionalen Problemumgehungen auflisten.

Problemumgehung: (produktionscode)

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top