为什么 BackgroundWorker.ProgressChanged 在 DoWork 完成之前不会被调用

本文关键字:调用 ProgressChanged BackgroundWorker DoWork 为什么 | 更新日期: 2023-09-27 18:37:24

之前对类似问题的回答建议用户,他们可能没有足够的时间在DoWork上调用ProgressChanged。 但我的计算很长 - 它们至少需要30秒来计算循环内每个站点计算的值。
在调试器中单步执行代码时,DoWork 会被调用并调用 ReportProgress。 但是,即使 DoWork 由于循环完成而完成,也不会立即调用 RunWorkerDone。以下是事件的顺序:

  1. DoWork 被调用
  2. 主线程继续循环,而 isBusy 为 true
  3. 即使 DoWork 完成了循环,它也没有完成,但主线程在 while 循环中继续,因为 isBusy 和 bgw.isBusy还是真的。 所以我在调试器中将 isBusy 重置为 false。 这结束主线程的 while 循环。
  4. BGW.Dispose() 从主线程调用
  5. BGW.ProgressChanged 被调用
  6. 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 

为什么 BackgroundWorker.ProgressChanged 在 DoWork 完成之前不会被调用

你在 BGW 运行时阻止了 UI 线程。 除了 DoWork 之外,BGW 的所有事件处理程序都封送到 UI 线程。 由于它被阻止了,他们只是坐在消息队列中,直到您的工作线程结束。

如果您只是让 UI 线程坐在那里阻塞直到完成,那么使用 BGW 的整个目的就会失败。 你最好只在 UI 线程上做工作。

应删除在工作线程工作时阻止 UI 线程的代码。 如果要在工作线程完成时在 UI 线程中执行代码,请使用 RunWorkerCompleted 事件。