为什么在DoWork完成之后才调用BackgroundWorker.ProgressChanged?

时间:2013-10-29 17:15:09

标签: c# multithreading backgroundworker

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

  1. 调用DoWork
  2. 当isBusy为真时,主线程继续循环
  3. 即使DoWork完成循环,它也没有完成,但主线程在while循环中继续,因为isBusy和bgw.isBusy 仍然是真的。所以我在调试器中将isBusy重置为false。这个 结束主线程的while循环。
  4. bgw.Dispose()从主线程
  5. 调用
  6. bgw.ProgressChanged被调用
  7. bgw.RunWorkerCompleted被调用
  8. 我启动后台线程的唯一原因是能够显示进度。进度显示在对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 
    

1 个答案:

答案 0 :(得分:-1)

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

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

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