BackgroundWorker在没有启动项目时导致错误

时间:2012-02-21 20:22:33

标签: vb.net vsto backgroundworker

我在VSTO / VB中有一个使用BackgroundWorker工作正常的项目。它是一个需要信息网页的表单。网页可能需要一段时间,因此我使用BackgroundWorker调用表单。

然后我有一个添加了BackgroundWorker项目的Excel Addin项目。当我从Excel Addin项目调用表单并使用BackgroundWorker请求网页时,它可以抓取网页。但是在BackgroundWorker1_RunWorkerCompleted方法完成后完成的工作会导致错误消息:

“跨线程操作无效:控制'TabPage2'从其创建的线程以外的线程访问。”

为什么从Excel Addin项目调用后,BackgroundWorker项目不起作用?

我注意到当我将BackgroundWorker项目设置为“启动项目”时,没有生成错误。它与从Excel Addin项目调用此BackgroundWorker项目有关。

2 个答案:

答案 0 :(得分:1)

编辑:可能是我从非UI线程调用RunWorkerAsync()吗?

我有一个带有Ribbon类的Excel Addin项目。 Ribbon1.vb有一个按钮单击方法,用于创建第二个项目的实例,将从中调用后台工作程序:

Private Sub Btn_Click(ByVal sender As System.Object, ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) Handles Btn.Click

    Dim MySecondProject As SecondProject.Form1 = New SecondProject.Form1()
    MySecondProject.Show()

End Sub

MySecondProject然后在其自己的按钮单击方法中调用BackgroundWorker:

BackgroundWorker1.RunWorkerAsync()

然后,完成后,后台工作者正在尝试更新MySecondProject中的标签:

Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted

    SuccessLabel.Text = "Success!"

End Sub

当MySecondProject是启动项目时,后台工作人员会跟踪正确的线程并在完成后成功更新标签。使用Excel Addin作为启动项目,并在运行时实例化MySecondProject,后台工作人员似乎忘记了正确的线程。我应该手动在某处插入Invoke或BeginInvoke来帮助后台工作人员跟踪要更新的正确线程吗?

答案 1 :(得分:1)

因此,事实证明,从Ribbon启动的Form启动的Backgroundworker无法在处理结束时更新控件。我不确定为什么它可以从作为Startup项目启动的Form中工作,而它不能从Ribbon启动的表单中工作,但事实证明,你需要处理后台工作者失去UI线程的轨道

使用MethodInvoker,如下面的代码段所示:

Imports System.Windows.Forms

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        BackgroundWorker1.RunWorkerAsync()
    End Sub

    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        [do nothing]
    End Sub

    Private myString As String = "This is my string"

    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted

        If Label1.InvokeRequired Then
            Dim mi As MethodInvoker = AddressOf UpdateFormText
            Label1.BeginInvoke(mi)
        Else
            Label1.Text = myString
        End If

    End Sub

    Private Sub UpdateFormText()
        Label1.Text = myString + " (BeginInvoked)"
    End Sub

End Class

VS2010中更好的答案是使用内联MethodInvoker而不是第二个函数:

Me.Invoke(CType(Sub() Me.Label1.Text = "This is my string", MethodInvoker))