2010-03-15 58 views
8

我有一个后台工作者。在我调用worker之前,我禁用了一个按钮并使gif可见。然后我调用runworkerasync方法,它运行良好,直到comleteion。在'RunWorkerCompleted()'我得到一个交叉线程错误。任何想法为什么?BackgroundWorker不工作在VSTO

private void buttonRun_Click(object sender, EventArgs e) 
    { 
     if (comboBoxFiscalYear.SelectedIndex != -1 && !string.IsNullOrEmpty(textBoxFolderLoc.Text)) 
     { 
      try 
      { 
       u = new UpdateDispositionReports(
        Convert.ToInt32(comboBoxFiscalYear.SelectedItem.ToString()) 
        , textBoxFolderLoc.Text 
        , Properties.Settings.Default.TemplatePath 
        , Properties.Settings.Default.ConnStr); 
       this.buttonRun.Enabled = false; 
       this.pictureBox1.Visible = true; 

       BackgroundWorker bw = new BackgroundWorker(); 
       bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
       bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
       bw.RunWorkerAsync(); 
       //backgroundWorker1.RunWorkerAsync(); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show("Unable to process.\nError:" + ex.Message, Properties.Settings.Default.AppName); 
      } 
     } 
    } 

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     buttonRun.Enabled = true; 
     pictureBox1.Visible = false; 
    } 

    void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     u.Execute(); 
    } 
+1

请发布堆栈跟踪。 – 2010-03-15 18:42:24

回答

2

一些有关VSTO运行同一个线程中控制的后台工作。不确定。我必须检查InvokeRequired

private void buttonRun_Click(object sender, EventArgs e) 
    { 
     if (comboBoxFiscalYear.SelectedIndex != -1 && !string.IsNullOrEmpty(textBoxFolderLoc.Text)) 
     { 
      try 
      { 
       u = new UpdateDispositionReports(
        Convert.ToInt32(comboBoxFiscalYear.SelectedItem.ToString()) 
        , textBoxFolderLoc.Text 
        , Properties.Settings.Default.TemplatePath 
        , Properties.Settings.Default.ConnStr); 
       this.buttonRun.Enabled = false; 
       this.pictureBox1.Visible = true; 

       BackgroundWorker bw = new BackgroundWorker(); 
       bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
       bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
       bw.RunWorkerAsync(); 
       //backgroundWorker1.RunWorkerAsync(); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show("Unable to process.\nError:" + ex.Message, Properties.Settings.Default.AppName); 
      } 
     } 
    } 
    delegate void ReenableRunCallback(); 

    private void ReenableRun() 
    { 
     if (this.buttonRun.InvokeRequired) 
     { 
      ReenableRunCallback r = new ReenableRunCallback(ReenableRun); 
      this.buttonRun.Invoke(r, null); 
     } 
     else 
      this.buttonRun.Enabled = true; 
    } 
    private void HideProgress() 
    { 
     if (this.pictureBox1.InvokeRequired) 
     { 
      ReenableRunCallback r = new ReenableRunCallback(HideProgress); 
      this.pictureBox1.Invoke(r, null); 
     } 
     else 
      this.pictureBox1.Visible = false; 
    } 

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     ReenableRun(); 
     HideProgress(); 
    } 

    void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     u.Execute(); 
    } 
+2

+1您的按钮最初是从应用程序的第一个和主线程创建的,也称为GUI线程。然后,在RunWorkerCompleted上,尝试访问从前一个线程创建的按钮。然后,您需要验证您的按钮是否可以使用InvoqueRequired属性进行访问,然后按照您所做的那样重试通过invoed委托,以同步这两个线程。就是这个方法! – 2010-03-15 19:25:34

18

这似乎是VSTO和BackgroundWorker的问题。

解决方案是here

基本上你需要调用

System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext()); 

你打电话之前RunWorkerAsync。很棒。

为了避免每次在您的AddIn主类中都有一个静态成员时实例化对象并重用它。这样你只能实例化一次。

+1

这节省了我的周末。 – squillman 2012-12-14 17:51:24

+0

也为我节省了几个小时。 – OfficeAddinDev 2015-05-06 09:52:14

+0

认真吗?优秀的提示,但发现解决方案刚刚杀死了我下午的大部分时间。我需要一杯啤酒! – 2015-10-08 13:59:34