-1

之前对类似问题的回答建议用户,他们可能没有足够的时间在 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 
4

1 回答 1

-1

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

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

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

于 2013-10-29T17:24:10.520 回答