-1

同様の質問に対する以前の回答では、ProgressChanged を呼び出すには DoWork で十分な時間を費やせない可能性があるとユーザーにアドバイスしていました。しかし、私の計算は時間がかかります。ループ内の各ステーション計算の値を計算するには、少なくとも 30 秒かかります。
デバッガーでコードをステップ実行すると、DoWork が呼び出され、ReportProgress が呼び出されます。ただし、ループが完了して DoWork が終了しても、RunWorkerCompleted はすぐには呼び出されません。イベントの順序は次のとおりです。

  1. DoWorkが呼び出されます
  2. isBusy が true の間、メインスレッドはループし続けます
  3. DoWork がループを完了しても、ループは終了しませんが、isBusy と bgw.isBusy がまだ true であるため、メイン スレッドは while ループを続行します。そこで、デバッガーで isBusy を false にリセットしました。これにより、メイン スレッドの while ループが終了します。
  4. bgw.Dispose() はメインスレッドから呼び出されます
  5. bgw.ProgressChanged が呼び出されます
  6. bgw.RunWorkerCompleted が呼び出されます

バックグラウンド スレッドを開始した唯一の理由は、進行状況を表示できるようにするためです。進行状況は、SetStatusBar の呼び出しに表示されます。バックグラウンド スレッドを開始しない場合は、MessageBox.Show 関数呼び出しで進行状況を表示できます。ただし、これには、107 のステーションのそれぞれが計算された後に、ユーザーが [OK] をクリックする必要があります。計算が進むにつれてステーションを表示する方法を見つけようとしています。ループで SetStatusBar を呼び出すだけでは、明らかに GUI を更新する時間がありません。だから私の質問は、ループが完了した後ではなく、ループ中にステータスメッセージを表示する方法です。

これが私のコードです:

Boolean isBusy = true;
// setting up a BackgroundWorker because the screen needs time to redraw
BackgroundWorker bgw = new BackgroundWorker();
bgw.WorkerSupportsCancellation = true;
bgw.WorkerReportsProgress = true;
bgw.DoWork += delegate
{
  do
  {
    isOK = CreateAverageRatingsComparisonCSV(stationIndex, out stationTitle);
    stationIndex++;
    count++;
    int percent = (int)(100 * count / numStations);
    if (percent == 0)
      percent = 1;
    bgw.ReportProgress(percent, stationTitle);
  } while (isOK && stationTitle.Length > 0);
};

bgw.RunWorkerCompleted += delegate
{
  isBusy = false;
};
bgw.ProgressChanged += new ProgressChangedEventHandler(bgworker_ProgressChanged); 
bgw.RunWorkerAsync();

// wait a 1/2 second at a time for BGW to finish      
while (bgw.IsBusy && isBusy)
{             
  System.Threading.Thread.Sleep(500);
}
bgw.Dispose();

//////////////////////////////////////////
private void bgworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  //display stationTitle
  SetStatusBar("Message", (string)e.UserState);
}//END 
4

1 に答える 1

-1

BGW の実行中に UI スレッドをブロックしています。以外の BGW のすべてのイベント ハンドラはDoWork、UI スレッドにマーシャリングされます。ブロックされているため、ワーカーが終了するまで何もせずにメッセージ キューに留まっているだけです。

UIスレッドが完了するまでブロックしている場合、BGWを使用する目的全体が無効になります。代わりに、UI スレッドで作業を行う方がよいでしょう。

ワーカーの動作中に UI スレッドをブロックするコードを削除する必要があります。ワーカーの終了時に UI スレッドでコードを実行する場合は、RunWorkerCompletedイベントを使用します。

于 2013-10-29T17:24:10.520 に答える