C# 为什么在工作完成后才调用BackgroundWorker.ProgressChanged?

C# 为什么在工作完成后才调用BackgroundWorker.ProgressChanged?,c#,multithreading,backgroundworker,C#,Multithreading,Backgroundworker,之前对类似问题的回答建议用户,他们可能没有足够的时间花在工作上,无法打电话给ProgressChanged。但是我的计算很长——它们至少需要30秒来计算环路内每个站点的计算值。 通过在调试器中单步执行代码,DoWork确实会被调用并调用ReportProgress。但是,即使当DoWork由于循环完成而完成时,也不会立即调用RunWorkerCompleted。 以下是事件的顺序: 调用DoWork 当isBusy为true时,主线程继续循环 尽管DoWork完成了循环,但它并没有完成,但主线程

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

  • 调用DoWork
  • 当isBusy为true时,主线程继续循环
  • 尽管DoWork完成了循环,但它并没有完成,但主线程在while循环中继续,因为isBusy和bgw.isBusy 这仍然是事实。因此,我在调试器中将isBusy重置为false。这 结束主线程的while循环
  • 从主线程调用bgw.Dispose()
  • bgw.ProgressChanged被调用
  • 调用bgw.RunWorkerCompleted
  • 我启动后台线程的唯一原因是能够显示进度。进度显示在对SetStatusBar的调用中。如果我没有启动后台线程,我可以通过MessageBox.show函数调用显示进度。但这需要用户在计算完107个站点后单击OK。我正试图找到一种在计算过程中显示站点的方法。如果我只是在循环中调用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
    事件。

    是否尝试在ProgressChanged事件中仅设置一个断点并让代码运行?是否可能是SetStatusBar代码中的问题?是什么代码阻塞了UI线程?它是带有sleep命令的while循环吗?或者您的意思是运行的BGW被封送到被阻止的UI线程?阻止UI线程的代码是什么。@DianaCook当BGW未完成时,有UI线程睡眠的代码是阻止UI线程的代码。