2010-03-15 15 views
8

Tengo un trabajador de segundo plano. Antes de invocar al trabajador desactivo un botón y hago que un gif sea visible. Luego invoco el método runworkerasync y funciona bien hasta comleteion. En 'RunWorkerCompleted()' aparece un error de cruce de hilos. ¿Alguna idea de por qué?BackgroundWorker No funciona en 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

Por favor, publique el seguimiento de la pila. –

Respuesta

2

algo sobre VSTO ejecuta el trabajador de fondo en el mismo hilo que los controles. No es seguro. Tenía que comprobar la 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 Su botón se creó inicialmente a partir de su primer y principal hilo de la aplicación, también conocido como el hilo de la GUI. Luego, en RunWorkerCompleted, intenta acceder al botón que se creó a partir del hilo anterior. Luego, debe verificar si se puede acceder a su botón con la propiedad InvoqueRequired, luego reintentar a través de un delegado invocado como lo hizo, esto para sincronizar ambos hilos. ¡Esa es la manera! –

18

Parece ser un problema con VSTO y BackgroundWorker.

La solución es here.

Básicamente lo que necesita para llamar

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

antes de llamar RunWorkerAsync. Funciona genial.

Para evitar crear instancias del objeto cada vez que tenga un miembro estático en la clase principal de AddIn y reutilizarlo. De esta forma, solo creará una instancia una vez.

+1

Esto acaba de salvar mi fin de semana. – squillman

+0

Me salvó unas horas también. – OfficeAddinDev

+0

en serio? Excelente consejo, pero encontrar esa solución acaba de matar la mayor parte de mi tarde. Necesito una cerveza !! –