为什么 BackgroundWorker.ProgressChanged 在 DoWork 完成之前不会被调用
本文关键字:调用 ProgressChanged BackgroundWorker DoWork 为什么 | 更新日期: 2023-09-27 18:37:24
之前对类似问题的回答建议用户,他们可能没有足够的时间在DoWork上调用ProgressChanged。 但我的计算很长 - 它们至少需要30秒来计算循环内每个站点计算的值。
在调试器中单步执行代码时,DoWork 会被调用并调用 ReportProgress。 但是,即使 DoWork 由于循环完成而完成,也不会立即调用 RunWorkerDone。以下是事件的顺序:
- DoWork 被调用
- 主线程继续循环,而 isBusy 为 true
- 即使 DoWork 完成了循环,它也没有完成,但主线程在 while 循环中继续,因为 isBusy 和 bgw.isBusy还是真的。 所以我在调试器中将 isBusy 重置为 false。 这结束主线程的 while 循环。
- BGW.Dispose() 从主线程调用
- BGW.ProgressChanged 被调用
- BGW.RunWorkerComplete被调用
我启动后台线程的唯一原因是能够显示进度。 进度显示在对 SetStatusBar 的调用中。 如果我不启动后台线程,则可以使用 MessageBox.Show 函数调用显示进度。 但这需要用户在 107 个站点中的每一个计算后单击"确定"。 我正在尝试找到一种在计算过程中显示电台的方法。 显然,如果我只是在循环中调用 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
你在 BGW 运行时阻止了 UI 线程。 除了 DoWork
之外,BGW 的所有事件处理程序都封送到 UI 线程。 由于它被阻止了,他们只是坐在消息队列中,直到您的工作线程结束。
如果您只是让 UI 线程坐在那里阻塞直到完成,那么使用 BGW 的整个目的就会失败。 你最好只在 UI 线程上做工作。
应删除在工作线程工作时阻止 UI 线程的代码。 如果要在工作线程完成时在 UI 线程中执行代码,请使用 RunWorkerCompleted
事件。