同様の質問に対する以前の回答では、ProgressChanged を呼び出すには DoWork で十分な時間を費やせない可能性があるとユーザーにアドバイスしていました。しかし、私の計算は時間がかかります。ループ内の各ステーション計算の値を計算するには、少なくとも 30 秒かかります。
デバッガーでコードをステップ実行すると、DoWork が呼び出され、ReportProgress が呼び出されます。ただし、ループが完了して DoWork が終了しても、RunWorkerCompleted はすぐには呼び出されません。イベントの順序は次のとおりです。
- DoWorkが呼び出されます
- isBusy が true の間、メインスレッドはループし続けます
- DoWork がループを完了しても、ループは終了しませんが、isBusy と bgw.isBusy がまだ true であるため、メイン スレッドは while ループを続行します。そこで、デバッガーで isBusy を false にリセットしました。これにより、メイン スレッドの while ループが終了します。
- bgw.Dispose() はメインスレッドから呼び出されます
- bgw.ProgressChanged が呼び出されます
- 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