Fernando
Fernando

Reputation: 39

C# Backgroundworker ReportProgress() not executing

Hello I am trying to populate a progress bar but the ReportProgress call its not been executed for some reason.

Here is my code

    //create status_Worker
    status_Worker = new BackgroundWorker();
    status_Worker.DoWork += new DoWorkEventHandler(Status_DoWork);
    status_Worker.ProgressChanged += new ProgressChangedEventHandler(Worker_ProgressChanged);
    status_Worker.WorkerReportsProgress = true;
    status_Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);

    private void Status_DoWork(object sender, DoWorkEventArgs e)
    {
        //make call to Logger class getStatus method
        _logger.getStatus(sender);
    }

    private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressbar1.Value = e.ProgressPercentage;
    }

    private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            MessageBox.Show(e.Error.Message);
            return;
        } 
        else
        {
            Start_button.IsEnabled = true;
        }

    }

    private void Start_button_Click(object sender, RoutedEventArgs e)
    {
        //initiate status_Worker when button is clicked
        status_Worker.RunWorkerAsync();
        Start_button.IsEnabled = false;
    }

Now inside the Logger class I have the getStatus() method. i make a call to a local server to get status of the files been processed and all that works and I see the values been updated automatically on my MainWindow.Status.

    public async Task getStatus(object sender)
    {
        BackgroundWorker statusWorker = (BackgroundWorker)sender;
        //Making a call to ReportProgress here works and it shows the progress bar
        //statusWorker.ReportProgress(99);

        //REQUEST STATUS from a server
        //Status format
        //CurrentParser, NumberOfFilesToParse,CountOfCompletedFiles,Status, NumberOfProcessRunning
        int CountOfCompletedFiles;
        int NumberOfFilesToParse;
        int percent;
        string status = "Running";
        string[] stats;
        char[] delimiterChars = { ' ', ',', '.', ':', '\t' };

        while(status!="Complete")
        {

            var getstatus = await request.GetStringAsync("http://localhost:8085/status");
            logs.Add(getstatus);
            stats = getstatus.Split(delimiterChars);
            NumberOfFilesToParse = Int32.Parse(stats[1]);
            CountOfCompletedFiles = Int32.Parse(stats[2]);
            status = stats[3];

            Thread.Sleep(1000);
            MainWindow.main.Status = "Files to process: " + NumberOfFilesToParse + " Files completed: " + CountOfCompletedFiles + " Status: " + status;

            if(NumberOfFilesToParse!=0 && status!="Complete")
            {
                percent = (CountOfCompletedFiles * 100) / NumberOfFilesToParse;
                //a call to ReportProgress here stalls the program at this point
                //statusWorker.ReportProgress(percent);
            }

        }
        MainWindow.main.Status = "Completed!";

    }

A call to ReportProgress at the start of the getStatus method works but a call to ReportProgress during or after my while loop results in process stalling at that point. Even when using static numbers ReportProgress(99) it only executes at the beginning

Upvotes: 0

Views: 291

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456437

Your Status_DoWork method is doing fire-and-forget. It's calling an async Task method and then ignoring the Task it returns.

One of the problems you've run into is that BackgroundWorker simply doesn't work with async. What's actually happening is that as soon as the first await is reached in getStatus, it returns an incomplete Task to Status_DoWork, which then exits. This causes the BackgroundWorker to finish, so raising progress events no longer makes sense for that BackgroundWorker.

The modern replacement for BackgroundWorker is Task.Run, which includes support for progress reporting. Ideally, you would only use Task.Run for CPU-bound methods, not the I/O-bound methods:

private void Start_button_Click(object sender, RoutedEventArgs e)
{
  Start_button.IsEnabled = false;
  var progress = new Progress<int>(update => progressbar1.Value = update);
  try
  {
    await _logger.getStatus(progress);
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message);
  }
  finally
  {
    Start_button.IsEnabled = true;
  }
}

public async Task getStatus(IProgress<int> progress)
{
  int CountOfCompletedFiles;
  int NumberOfFilesToParse;
  int percent;
  string status = "Running";
  string[] stats;
  char[] delimiterChars = { ' ', ',', '.', ':', '\t' };

  while(status!="Complete")
  {
    var getstatus = await request.GetStringAsync("http://localhost:8085/status");
    logs.Add(getstatus);
    stats = getstatus.Split(delimiterChars);
    NumberOfFilesToParse = Int32.Parse(stats[1]);
    CountOfCompletedFiles = Int32.Parse(stats[2]);
    status = stats[3];

    await Task.Run(() => Thread.Sleep(1000)); // process file in Task.Run
    MainWindow.main.Status = "Files to process: " + NumberOfFilesToParse + " Files completed: " + CountOfCompletedFiles + " Status: " + status;

    if(NumberOfFilesToParse!=0 && status!="Complete")
    {
      percent = (CountOfCompletedFiles * 100) / NumberOfFilesToParse;
      progress.Report(percent);
    }
  }
  MainWindow.main.Status = "Completed!";
}

Upvotes: 2

Related Questions