从Async回调方法与UI线程交互?

我有一个在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 

这会在方法完成后导致exception。 (当执行End Sub时)

撤消操作遇到的上下文与相应的Set操作中应用的上下文不同。 可能的原因是在线程上设置了上下文而没有恢复(撤消)。

那么我如何从回调方法中与UI线程进行交互呢? 我究竟做错了什么?

您必须在frmMain对象上使用Invoke或BeginInvoke来排队要在UI线程上执行的消息(委托)。

这是我在C#中的表现。

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

另请查看此Invoke类型列表及其用法 。

特拉维斯是对的。 Windows窗体应用程序是单线程的,您无法从任何其他线程访问UI。 您需要使用BeginInvoke对UI线程的调用进行编组。

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

您需要让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 

我找到了解决方法(实际上是解决方法!),当我在UI线程上从一个Form中交互甚至读取一个属性时,我遇到了反复出现的InvalidContextException错误。

在从Async回调方法与UI线程交互之前和之后,我不得不备份和恢复执行上下文。 然后exception就像它出现的那样神秘地消失了,你可以读取/写入属性,调用方法,基本上用你的Async回调同步做你喜欢的UI线程,而不必使用委托或调用!

这个例外实际上是.NET framewok本身的一个低级错误。 请参阅Microsoft Connect错误报告 ,但请注意它们没有列出function解决方法。

解决方法:(生产代码)

 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