views:

216

answers:

2

I have a background worker. Before I invoke the worker I disable a button and make a gif visible. I then invoke the runworkerasync method and it runs fine until comleteion. On the 'RunWorkerCompleted()' I get a cross thread error. Any idea why?

    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();
    }
A: 

It might be because your background thread is accessing your main thread's UpdateDispositionReports instance. Try instantiating it in the DoWork handler. Also, pass the parameters for UpdateDispositionReports() to the BackGroundWorker via RunWorkerAsync(). (You will have to create a class or struct to hold the parameters).

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    // get your parameters from e.Argument here

    UpdateDispositionReports myU = new UpdateDispositionReports(your parameters here);

    myU.Execute();
}
Charles
+1  A: 

something about VSTO running the background worker on the same thread as the controls. Not sure. I had to check the 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();
    }
Chris
+1 Your button was initially created from your first and main thread of the application, also know as the GUI thread. Then, on RunWorkerCompleted, you try to access the button that has been created from previous thread. Then, you need to verify whether your button can be accessed with the InvoqueRequired property, then retrying through an invoed delegate as you did, this to synchronize both threads. That's the way!
Will Marcouiller