.net 后台工作线程问题
在尝试实现一个简单的BackgroundWorker时,我遇到了臭名昭著的“Cross thread operation not valid”异常。我花了几个小时阅读了我能找到的关于这个主题的所有东西,包括许多相关的问题,但我就是不明白 我有一个简单的winform,它有一个DoWork()方法:.net 后台工作线程问题,.net,vb.net,winforms,backgroundworker,.net,Vb.net,Winforms,Backgroundworker,在尝试实现一个简单的BackgroundWorker时,我遇到了臭名昭著的“Cross thread operation not valid”异常。我花了几个小时阅读了我能找到的关于这个主题的所有东西,包括许多相关的问题,但我就是不明白 我有一个简单的winform,它有一个DoWork()方法: 它需要一个代表要完成的工作的委托 它创建一个BackgroundWorker,并将委托分配给DoWork事件 它调用RunWorkerAsync() RunWorkerCompleted()调用的函数
BackgroundWorker
,并将委托分配给DoWork
事件RunWorkerAsync()
RunWorkerCompleted()
调用的函数尝试更新表单上的标签,但引发跨线程异常
Public Class MyForm
Public Sub DoWork(workToDo As DoWorkEventHandler)
Dim worker As New BackgroundWorker()
worker.WorkerReportsProgress = True
worker.WorkerSupportsCancellation = True
AddHandler worker.DoWork, workToDo
AddHandler worker.RunWorkerCompleted, AddressOf WorkerCompleted
worker.RunWorkerAsync()
End Sub
Private Sub WorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
resultLabel.Text = "Done!" ' Exception thrown here
End Sub
End Class
因此,看起来WorkerCompleted
正在后台线程上运行。我是否接近一个有效的解决方案,或者我没有掌握基本原理
更新:一个神秘的补丁
我发现了一个愚蠢的运气。我们得进一步查一下申请表。这是VSTO Excel加载项的一部分。我正在功能区加载事件中实例化表单,然后在单击按钮时调用Show()
。这引发了一个例外
Private Sub Ribbon1Load(ByVal sender As System.Object, ByVal e As RibbonUIEventArgs) Handles MyBase.Load
mProcessing = New MyForm()
End Sub
Private Sub Button1Click(sender As System.Object, e As RibbonControlEventArgs) Handles Button1.Click
mProcessing.Show()
mProcessing.DoWork(AddressOf UpdateData)
End Sub
将
mpprocessing=New MyForm()
移动到单击处理程序可消除异常。一切进展顺利。我来回移动了几次代码,并对问题/解决方案充满信心 RunWorkerCompleted事件通常与BackgroundWorker
本身(UI线程)在同一线程上运行,因此我怀疑这是问题所在。我怀疑您的错误是在DoWork
方法中发生的,只是在您点击UI线程时被抛出。国家:
在访问RunWorkerCompletedEventArgs.Result属性之前,RunWorkerCompletedEventArgs.Error和AsyncCompletedEventArgs.Cancelled属性应始终检查。如果引发异常或操作被取消,访问RunWorkerCompletedEventArgs.Result属性将引发异常
Private Sub Ribbon1Load(ByVal sender As System.Object, ByVal e As RibbonUIEventArgs) Handles MyBase.Load
mProcessing = New MyForm()
End Sub
Private Sub Button1Click(sender As System.Object, e As RibbonControlEventArgs) Handles Button1.Click
mProcessing.Show()
mProcessing.DoWork(AddressOf UpdateData)
End Sub
如果您遇到UI线程上未运行的RunWorkerCompleted
事件的问题,则您可以始终使用invoke
调用UI更新以在正确的线程上运行,例如
resultLabel.Invoke(Sub() resultLabel.Text = "Done!")
我看不出有什么不对劲,但这是可能发生的。我没怎么见过,但我见过,不得不这样处理:
If Me.InvokeRequired Then
Me.BeginInvoke(Sub() resultLabel.Text = "Done!")
Else
resultLabel.Text = "Done!"
End If
对我有用。请举例说明这个问题。@Steven:我偶然发现了一个解决方案。请参阅我的更新。一般诊断是,当功能区的加载事件触发时,System.Threading.SynchronizationContext.Current为Nothing。您可以使用调试器检查的内容。这是非常不健康的,指向一个更大的潜在问题,一个你不应该忽视的问题;我只是在发帖时删减了代码。查看我的更新。