在尝试实现简单的BackgroundWorker时,我得到了臭名昭着的“跨线程操作无效”异常。我花了几个小时阅读关于这个主题的所有内容,包括关于SO的许多相关问题,但我只是没有得到它。
我有一个简单的winform,它有一个DoWork()方法:
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加载项的一部分。我在功能区Load事件中实例化我的表单,然后在单击按钮时调用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
将mProcessing = New MyForm()
移动到Click处理程序可以消除异常。一切都运作良好。我来回移动代码几次,对问题/解决方案充满信心。
答案 0 :(得分:2)
RunWorkerCompleted
事件通常在与BackgroundWorker
本身(UI线程)相同的线程上运行,所以我怀疑这是问题所在。我怀疑你的错误是在DoWork
方法期间发生的,只是在你点击UI线程后被抛出。 docs州:
在访问RunWorkerCompletedEventArgs.Result属性之前,RunWorkerCompleted事件处理程序应始终检查AsyncCompletedEventArgs.Error和AsyncCompletedEventArgs.Cancelled属性。如果引发异常或操作被取消,则访问RunWorkerCompletedEventArgs.Result属性会引发异常。
如果你 遇到问题,而{/ 1}}事件没有在UI线程上运行,那么你总是可以调用UI更新,使用{{}在正确的线程上运行1}}例如
RunWorkerCompleted
答案 1 :(得分:1)
我手边没有看到任何错误,但这可能发生。我没有看到太多,但我已经看到它,并且必须像这样处理它:
If Me.InvokeRequired Then
Me.BeginInvoke(Sub() resultLabel.Text = "Done!")
Else
resultLabel.Text = "Done!"
End If