2 Stimmen

Ungültige Cross-Thread-Operationen von BackgroundWorker2_RunWorkerCompleted in C#

Ich erhalte eine Fehlermeldung, die keinen Sinn ergibt.

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

In meiner Anwendung feuert der UI-Thread Folgendes ab backgroundWorker1 der, wenn er fast vollständig ist, Folgendes abfeuert backgroundWorker2 und wartet, bis sie abgeschlossen ist. backgroundWorker1 wartet auf backgroundWorker2 zu beenden, bevor sie abgeschlossen ist. AutoResetEvent Variablen werden verwendet, um zu kennzeichnen, wann jeder der Arbeiter fertig ist. Unter backgroundWorker2_RunWorkerComplete wird eine Funktion aufgerufen, die die Steuerelemente des Formulars zurücksetzt. Es ist in dieser ResetFormControls() Funktion, bei der die Ausnahme ausgelöst wird. Ich dachte, es sei sicher, die Formularsteuerelemente in der RunWorkerCompleted Funktion. Beide Background Worker werden vom UI-Thread instanziiert. Hier ist eine stark zusammengefasste Version von dem, was ich tue:

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

Ich würde mich über jeden Gedanken oder Vorschlag freuen. Ich verwende Microsoft Visual C# 2008 Express Edition. Danke.

5voto

Ragoczy Punkte 2827

RunWorkerCompleted wird auf dem Thread ausgeführt, der den BackgroundWorker gestartet hat. Da Sie BackgroundWorker verketten (2 von 1 starten), wird RunWorkerCompleted von 2 auf dem Thread von 1 ausgeführt, nicht auf dem UI-Thread.

Sie möchten zurück zum UI-Thread mit Invoke marshall oder verschieben Sie die UI-Aktualisierung auf 1's RunWorkerCompleted.

Mein Vorschlag wäre, bei der Aktualisierung der Benutzeroberfläche immer auf InvokeRequired zu prüfen, so dass Sie sich keine Gedanken darüber machen müssen, von welchem Thread es kommt.

1voto

Stephen Cleary Punkte 402664

BackgroundWorker-Objekte können nicht verschachtelt werden. Ich empfehle die Verwendung von .NET 4.0 Tasks, wenn überhaupt möglich, da diese verschachtelt werden können.

Die Verschachtelung von BGWs ist nur möglich, wenn man etwas wie den ActionDispatcher aus dem Nito.Async Bibliothek.

0voto

Will Marcouiller Punkte 23205

Der Zugriff auf Steuerelemente innerhalb eines anderen Threads ist niemals thread-sicher.

Ihre Frage lautet: "Wie kann ich über einen anderen Thread auf ein vom UI-Thread erstelltes Steuerelement zugreifen?"

Die Antwort ist, dass Sie sich auf Ihre Kontrolle berufen. Hier ist eine Link wo Sie ein Codebeispiel sehen können, das dies ermöglicht.

Genügt das Ihren Ansprüchen?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X