2010-03-15 16 views
8

Mam pracownika tła. Zanim wezwę pracownika, wyłączę przycisk i pokażę gif. Następnie wywołuję metodę runworkerasync i działa ona dobrze do ukończenia. W "RunWorkerCompleted()" otrzymuję błąd wątku krzyżowego. Każdy pomysł, dlaczego?BackgroundWorker Nie działa w 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

Proszę zaksięgować ślad stosu. –

Odpowiedz

2

coś o VSTO działającego w tle na tym samym wątku, co elementy sterujące. Niepewny. Musiałem sprawdzić 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 Twój przycisk został początkowo utworzony z pierwszego i głównego wątku aplikacji, znanego również jako wątek GUI. Następnie, w RunWorkerCompleted, próbujesz uzyskać dostęp do przycisku, który został utworzony z poprzedniego wątku. Następnie należy sprawdzić, czy dostęp do przycisku można uzyskać za pomocą właściwości InvoqueRequired, a następnie ponawiać próbę za pośrednictwem faktycznego delegata, tak jak w przypadku synchronizacji obu wątków. To jest sposób! –

18

wydaje się być problem z VSTO i BackgroundWorker.

Rozwiązaniem jest here.

Zasadniczo trzeba zadzwonić

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

przed wywołaniem RunWorkerAsync. Działa świetnie.

Aby uniknąć tworzenia instancji obiektu za każdym razem, gdy możesz mieć statycznego członka klasy głównej AddIn i użyć go ponownie. W ten sposób tylko raz utworzysz instancję.

+1

To właśnie uratowało mój weekend. – squillman

+0

Uratował mnie też kilka godzin. – OfficeAddinDev

+0

Poważnie? Doskonała wskazówka, ale znalezienie tego rozwiązania zabiło większość mojego popołudnia. Potrzebuję piwa !! –

Powiązane problemy