繁体   English   中英

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

[英]Interacting with the UI thread from an Async callback method?

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

撤消操作遇到的上下文与相应的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线程交互之前和之后,我不得不备份和恢复执行上下文。 然后异常就像它出现时一样神秘地消失了,你可以读取/写入属性,调用方法,基本上用你的Async回调同步做你喜欢的UI线程,而不必使用委托或调用!

这个例外实际上是.NET framewok本身的一个低级错误。 请参阅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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM