【问题标题】:Why BackgroundWorker.ProgressChanged is not called until after DoWork is completed?为什么在 DoWork 完成之前不调用 BackgroundWorker.ProgressChanged?
【发布时间】:2013-10-30 01:26:49
【问题描述】:

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

  1. DoWork 被调用
  2. 当 isBusy 为真时,主线程继续循环
  3. 尽管 DoWork 完成了循环,但它并没有完成,但主线程继续在 while 循环中,因为 isBusy 和 bgw.isBusy 仍然是真的。所以我在调试器中将 isBusy 重置为 false。这个 结束主线程的while循环。
  4. bgw.Dispose() 从主线程调用
  5. bgw.ProgressChanged 被调用
  6. bgw.RunWorkerCompleted 被调用

我启动后台线程的唯一原因是能够显示进度。进度显示在对 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 

【问题讨论】:

  • 您是否尝试在 ProgressChanged 事件中仅设置一个断点并让代码运行?问题可能出在 SetStatusBar 代码中吗?

标签: c# multithreading backgroundworker


【解决方案1】:

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

如果你只是让 UI 线程在那里阻塞直到它完成,那么使用 BGW 的整个目的就被破坏了。你最好只在 UI 线程上做正确的工作。

您应该删除在工作线程工作时阻塞 UI 线程的代码。如果您想在工作人员完成时在 UI 线程中执行代码,请使用 RunWorkerCompleted 事件。

【讨论】:

  • 什么代码阻塞了 UI 线程?是带有 sleep 命令的 while 循环吗?或者你的意思是BGW运行被编组到被阻塞的UI线程?什么是阻塞 UI 线程的代码。
  • @DianaCook 在 BGW 未完成时让 UI 线程休眠的代码是阻塞 UI 线程的原因。
猜你喜欢
  • 2013-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多