Interagir avec le thread d'interface utilisateur à partir d'une méthode de rappel Async?
-
20-09-2019 - |
Question
I ai un procédé qui est appelé de manière asynchrone quand
La solution Vous devez utiliser Invoke ou BeginInvoke sur l'objet frmMain à un message enqueue (un délégué) à exécuter sur le thread d'interface utilisateur. Voici comment je le ferais en C #. Consultez également cette des types Invoke et leurs utilisations . frmMain.Invoke(() => frmMain.refreshStats(d1, d2));
Autres conseils
Travis est correct. l'application Windows Forms sont un seul thread, vous ne pouvez pas accéder à l'interface d'un autre fil. Vous devez marshall l'appel à thread d'interface utilisateur en utilisant BeginInvoke.
Voir: http://msdn.microsoft.com/en-us /library/0b1bf3y3.aspx
Vous devez avoir l'interface utilisateur fil invoquez la méthode de frmMain.refreshStats. Il est-bien sûr plusieurs façons de le faire en utilisant la propriété Control.InvokeRequired et Control.Invoke ( MSDN Documentation ).
Vous pouvez avoir la méthode « EndAsync » faire le thread d'interface d'appel de méthode sûre, ou avoir la méthode refreshStats pour vérifier la sécurité des threads (en utilisant Control.InvokeRequired).
UI EndAsync thread-safe serait quelque chose comme ceci:
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
Ou vous pouvez avoir la méthode refreshStats vérifier pour voir si elle a besoin de se prévaloir sous le thread d'interface utilisateur:
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
J'ai trouvé la solution (solution, en fait!) À cette erreur de InvalidContextException récurrentes que je suis quand j'interagi ou même lire une propriété d'un formulaire sur le thread d'interface utilisateur.
Je devais sauvegarder et restaurer le contexte d'exécution, avant et après l'interaction avec le thread d'interface utilisateur de ma méthode de rappel Async. Puis l'exception disparaît aussi mystérieusement qu'il est apparu, et vous pouvez lire / propriétés d'écriture, les méthodes d'appel et de faire tout ce que vous voulez avec le fil de l'interface utilisateur, de manière synchrone à partir de votre rappel Async, sans avoir à utiliser des délégués ou lorsqu'il invoque!
Cette exception est en fait un bug au niveau bas dans le .NET se Framewok. Voir rapport Microsoft Connect bug , mais notez que la liste qu'ils pas de solutions fonctionnelles.
Solution: (code de production)
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