C# - Using BackgroundWorker.ReportProgress to update ProgressBar with custom Maximum value

11,582

Solution 1

If you look closely to the signatures available for the ReportProgress method you will notice that there is an overload that allows passing an object of your own in addition to the percentage of the work done.
This second parameter could be an instance of a reference type but it could also be a simple integer value like the number of pages for your current PDF.

The value passed as second parameter to ReportProgress could be retrieved in the event handler as the value for the ProgressChangedEventArgs.UserState property

So you could use it to pass the pageCount variable before starting the loop in the DoWork method along with a conventional value of -1 for the ProgressPercentage value

private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
  if (!backgroundWorker1.CancellationPending)
  {

    int pageCount = CalculatePageCount();
    backgroundWorker1.ReportProgress(-1, pageCount); 
    for (var pageNumber = 1; pageNumber <= pageCount; pageNumber++)
       ..... 

  }
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  // First call, the percentage is negative to signal that UserState
  // contains the number of pages we loop on....
  if(e.ProgressPercentage == -1)
     progressBar1.Maximum = Convert.ToInt32(e.UserState);
  else
     progressBar1.Value = e.ProgressPercentage;
}

Solution 2

...or just report the value as (int)(pageNumber * 100 / totalPages)

Share:
11,582
Adam Elders
Author by

Adam Elders

Updated on June 05, 2022

Comments

  • Adam Elders
    Adam Elders almost 2 years

    I've been searching for a couple of days on this topic and I haven't come across anything that seems relevant. Please keep in mind that I am still learning how to use BackgroundWorker and multi-threading in C#.

    I am having a problem using the ReportProgress method. Here is a small example of what I am doing.

    private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
      if (!backgroundWorker1.CancellationPending)
      {
        // bunch of code for handling a multiple-page PDF file using Ghostscript.NET
        for (var pageNumber = 1; pageNumber <= pageCount; pageNumber++)
        {
          if (!backgroundWorker1.CancellationPending)
          {
            // get file path and file name, convert page to image file
            // after converting page to image file do:
            backgroundWorker1.ReportProgress(pageNumber); // Here is the problem
          }
          else
            e.Cancel = true;
          ...
        }
      }
    }
    
    private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
    {
      progressBar1.Value = e.ProgressPercentage;
    }
    

    The problem that I'm having is that I want to provide users a progress bar that will update the progress as the file is being converted so that the UI does not become unresponsive. The progress bar's Maximum value property is set to 100, but obviously each PDF file will not be 100 pages - and the above code is only reporting the progressPercent value as each individual page - so the progress bar will only partially fill if the PDF is not 100 pages.

    So here's my question: how do I use the ReportProgress method to update the progress bar appropriately? I had the program working earlier by setting the maximum value before reporting progress (by using Invoke inside of DoWork). However, I've recently learned that you should not update the UI using BackgroundWorker's DoWork event (still researching that). So if ReportProgress only takes an integer value, how do I update the progress bar with the correct percentage? Obviously, I can't report "16.67%" using ReportProgress.

    Thanks in advance for your time and advice.