Domanda

Ricevo un errore che non ha senso.

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

Nella mia applicazione, i fuochi thread UI off backgroundWorker1, che quando gli incendi quasi complete off backgroundWorker2 e aspetta che sia completato. backgroundWorker1 attende backgroundWorker2 al completo, prima del completamento. variabili AutoResetEvent vengono utilizzate per la bandiera quando ciascuno dei lavoratori completare. In backgroundWorker2_RunWorkerComplete viene chiamata una funzione che resetta i controlli di modulo. E 'in questa funzione ResetFormControls() in cui viene lanciata l'eccezione. Ho pensato che fosse sicuro di modificare i controlli dei moduli nella funzione RunWorkerCompleted. Entrambi i lavoratori di sfondo sono istanziati dal thread dell'interfaccia utente. Ecco una versione notevolmente riassunto di quello che sto facendo:

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

Tutti i pensieri o suggerimenti che potete avere sarebbe apprezzato. Sto usando Microsoft Visual C # 2008 Express Edition. Grazie.

È stato utile?

Soluzione

RunWorkerCompleted sta per eseguire sul thread che ha iniziato il BackgroundWorker. Dal momento che stai concatenamento BackgroundWorkers (a partire dal 2 1), 2 di RunWorkerCompleted è in esecuzione su thread 1 di, non il thread dell'interfaccia utente.

Ti consigliamo di Marshall torna al thread UI con Invoke o spostare l'aggiornamento dell'interfaccia utente a 1 di RunWorkerCompleted.

Il mio suggerimento sarebbe quello di controllare sempre per InvokeRequired quando si aggiorna l'interfaccia utente, in questo modo non c'è bisogno di preoccuparsi di ciò che filo è venuta da.

Altri suggerimenti

oggetti BackgroundWorker non possono essere nidificate. Mi consiglia di utilizzare .NET 4.0 Compiti se possibile, dal momento che fanno il nido.

Nesting BGWs è possibile solo utilizzando qualcosa come ActionDispatcher dal Nito.Async biblioteca.

Accesso controlli all'interno di un altro thread non sarà mai threadsafe.

La tua domanda è: "Come posso accedere ad un controllo creato dal thread UI utilizzando un altro thread"

La risposta è invocando il vostro controllo. Ecco un dove si può vedere un esempio di codice permettendo così.

Questo fa quello che ti serve?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top