在尝试实现简单的BackgroundWorker 时,我遇到了臭名昭著的“跨线程操作无效”异常。我花了几个小时阅读我能找到的有关该主题的所有内容,包括有关 SO 的许多相关问题,但我就是不明白。
我有一个简单的 winform,它有一个 DoWork() 方法:
- 需要一个代表来代表要完成的工作。
- 它创建一个
BackgroundWorker
并将委托(delegate)分配给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 处理程序可消除该异常。一切都运转良好。我来回移动了代码几次,并对问题/解决方案充满信心。
最佳答案
RunWorkerCompleted
事件通常与 BackgroundWorker
本身(UI 线程)在同一线程上运行,所以我怀疑这就是问题所在。我怀疑您的错误是在 DoWork 方法期间发生的,并且在您点击 UI 线程后才被抛出。 docs状态:
Your RunWorkerCompleted event handler should always check the AsyncCompletedEventArgs.Error and AsyncCompletedEventArgs.Cancelled properties before accessing the RunWorkerCompletedEventArgs.Result property. If an exception was raised or if the operation was canceled, accessing the RunWorkerCompletedEventArgs.Result property raises an exception.
如果您遇到 RunWorkerCompleted
事件未在 UI 线程上运行的问题,那么您始终可以调用 UI 更新以在正确的线程上运行使用 Invoke
例如
resultLabel.Invoke(Sub() resultLabel.Text = "Done!")
关于.net - BackgroundWorker线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18103619/