BackgroundWorker线程问题

时间:2013-08-07 12:38:35

标签: .net vb.net winforms backgroundworker

在尝试实现简单的BackgroundWorker时,我得到了臭名昭着的“跨线程操作无效”异常。我花了几个小时阅读关于这个主题的所有内容,包括关于SO的许多相关问题,但我只是没有得到它。

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

  1. 需要代表工作的代表。
  2. 创建BackgroundWorker并将代理人分配给DoWork事件。
  3. 它会调用RunWorkerAsync()
  4. 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处理程序可以消除异常。一切都运作良好。我来回移动代码几次,对问题/解决方案充满信心。

2 个答案:

答案 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