.net - BackgroundWorker线程问题

标签 .net vb.net winforms backgroundworker

在尝试实现简单的BackgroundWorker 时,我遇到了臭名昭著的“跨线程操作无效”异常。我花了几个小时阅读我能找到的有关该主题的所有内容,包括有关 SO 的许多相关问题,但我就是不明白。

我有一个简单的 winform,它有一个 DoWork() 方法:

  1. 需要一个代表来代表要完成的工作。
  2. 它创建一个 BackgroundWorker 并将委托(delegate)分配给 DoWork 事件。
  3. 它调用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/

相关文章:

c# - C# 中的属性名称和方法名称可以相同吗?

vb.net - SQLite使用另一个表更新一个表中的列

c# - Asp.net Core Post 参数始终为 null

.net - 使用 SQL Server Express 部署桌面应用程序

vb.net - 将希腊字符转换为 Unicode

c# - 我有 FairlyLocal,但我需要它用于 VB 中的项目,但不支持函数 _()

c# - 带滚动条的控件上的 .NET C# MouseEnter 监听器

c# - 使用 this.validateChildren() 时如何针对所有无效表单控件设置 errorProvider?

c# - 如何在 winform 右上角单击(红色 X)按钮退出应用程序

c# - WCF 使用 MSMQ 发布/订阅