Invalid crossflow operations from BackgroundWorker2_RunWorkerCompleted in C #

I am getting an error that doesn't make sense.

Cross-thread operation not valid: Control 'buttonOpenFile' accessed from a thread other than the thread it was created on.

In my application, the UI thread fires backgroundWorker1

, which when it nearly completes, fires backgroundWorker2

and waits for it to complete. backgroundWorker1

waits backgroundWorker2

until it completes. AutoResetEvent

variables are used to mark when each of the workers is filled. A backgroundWorker2_RunWorkerComplete

function is called that resets the controls on the form. It is in this function ResetFormControls()

where the exception is thrown. I thought it was safe to change form controls in a function RunWorkerCompleted

. Both background artists are created from the UI thread. Here's a very generalized version of what I'm doing:

  AutoResetEvent evtProgrammingComplete_c = new AutoResetEvent(false);
  AutoResetEvent evtResetComplete_c = new AutoResetEvent(false);

  private void ResetFormControls()
  {
     toolStripProgressBar1.Enabled = false;
     toolStripProgressBar1.RightToLeftLayout = false;
     toolStripProgressBar1.Value = 0;

     buttonInit.Enabled = true;
     buttonOpenFile.Enabled = true; // Error occurs here.
     buttonProgram.Enabled = true;
     buttonAbort.Enabled = false;
     buttonReset.Enabled = true;
     checkBoxPeripheryModule.Enabled = true;
     checkBoxVerbose.Enabled = true;
     comboBoxComPort.Enabled = true;
     groupBoxToolSettings.Enabled = true;
     groupBoxNodeSettings.Enabled = true;
  }

  private void buttonProgram_Click(object sender, EventArgs e)
  {
     while (backgroundWorkerProgram.IsBusy)
        backgroundWorkerProgram.CancelAsync();

     backgroundWorkerProgram.RunWorkerAsync();
  }

  private void backgroundWorkerProgram_DoWork(object sender, DoWorkEventArgs e)
  {
     // Does a bunch of stuff...

     if (tProgramStat_c == eProgramStat_t.DONE)
     {
        tProgramStat_c = eProgramStat_t.RESETTING;

        while (backgroundWorkerReset.IsBusy)
           backgroundWorkerReset.CancelAsync();

        backgroundWorkerReset.RunWorkerAsync();
        evtResetComplete_c.WaitOne(LONG_ACK_WAIT * 2);

        if (tResetStat_c == eResetStat_t.COMPLETED)
           tProgramStat_c = eProgramStat_t.DONE;
     }
  }

  private void backgroundWorkerProgram_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
     // Updates form to report complete.  No problems here.

     evtProgrammingComplete_c.Set();
     backgroundWorkerProgram.Dispose();
  }

  private void backgroundWorkerReset_DoWork(object sender, DoWorkEventArgs e)
  {
     // Does a bunch of stuff...

     if (tResetStat_c == eResetStat_t.COMPLETED)
        if (tProgramStat_c == eProgramStat_t.RESETTING)
           evtProgrammingComplete_c.WaitOne();
  }

  private void backgroundWorkerReset_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
     CloseAllComms();
     ResetFormControls();
     evtResetComplete_c.Set();
     backgroundWorkerReset.Dispose();
  }

      

Any thoughts or suggestions that you may like will be greatly appreciated. I am using Microsoft Visual C # 2008 Express Edition. Thanks.

+2


a source to share


3 answers


RunWorkerCompleted will execute on the thread that started BackgroundWorker. Since you are binding BackgroundWorkers (starting at 2 of 1) the 2 RunWorkerCompleted runs on 1 thread, not the UI thread.

You will want to go back to the UI thread with Invoke, or move the UI update to 1 RunWorkerCompleted.



My suggestion was to always check for InvokeRequired when updating the UI, so you don't have to worry about which thread it is coming from.

+5


a source


BackgroundWorker objects cannot be nested. I recommend using .NET 4.0 tasks if at all possible as they have a socket.



BGW nesting is only possible with something like ActionDispatcher from the Nito.Async library .

+1


a source


Accessing controls on a different thread will never be thread safe.

Your question is, "How can I access a control created by a UI thread using a different thread?"

The answer is to challenge your control. Here's a link where you can see a sample code to enable this.

Does it do what you want it to do?

0


a source







All Articles