2

意味をなさないエラーが発生しています。

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

私のアプリケーションでは、UI スレッドが発火しbackgroundWorker1、ほぼ完了すると発火し、完了するbackgroundWorker2のを待ちます。 完了する前に完了する backgroundWorker1のを待ちます。変数は、各ワーカーが完了したときにフラグを立てるために使用されます。フォーム コントロールをリセットする関数が呼び出されます。例外がスローされるのは、この関数内です。関数内のフォーム コントロールを変更しても安全だと思いました。両方のバックグラウンド ワーカーは、UI スレッドからインスタンス化されます。これが私がやっていることの非常に要約されたバージョンです:backgroundWorker2AutoResetEventbackgroundWorker2_RunWorkerCompleteResetFormControls()RunWorkerCompleted

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

ご意見やご提案をいただければ幸いです。Microsoft Visual C# 2008 Express Edition を使用しています。ありがとう。

4

3 に答える 3

5

RunWorkerCompleted は、BackgroundWorker を開始したスレッドで実行されます。BackgroundWorkers (1 から 2 を開始) をチェーンしているため、2 の RunWorkerCompleted は UI スレッドではなく 1 のスレッドで実行されます。

Invoke を使用して UI スレッドにマーシャリングするか、UI の更新を 1 の RunWorkerCompleted に移動します。

私の提案は、UI を更新するときに常に InvokeRequired をチェックすることです。そうすれば、それがどのスレッドから来ているかを心配する必要はありません。

于 2010-05-12T16:05:26.430 に答える
1

BackgroundWorker オブジェクトはネストできません。.NET 4.0 タスクは入れ子になるため、可能な限り使用することをお勧めします。

BGW のネストは、 Nito.Asyncライブラリの ActionDispatcherなどを使用することによってのみ可能です。

于 2010-05-12T16:04:59.917 に答える
0

別のスレッド内のコントロールへのアクセスは、決してスレッドセーフではありません。

あなたの質問は、「別のスレッドを使用して UI スレッドによって作成されたコントロールにアクセスするにはどうすればよいですか?」です。

答えは、コントロールを呼び出すことです。これを許可するコード サンプルを確認できるリンクを次に示します。

これはあなたが必要とすることをしますか?

于 2010-05-12T16:05:11.383 に答える