0

I've created a loading form within my C# WinForms application that is shown during long processes. I've added a progress bar to my loading form that I would like to update to give some feedback of loading to the user.

Within my loading form code, I have created a new BackgroundWorker and added DoWork and ProgressChanged event handlers. The problem is that the backgroundWorker_ProgressChanged is not being called. I have inserted break points into the function and they are not caught.

Where am I going wrong? Any help appreciated. Thanks.

frmLoading:

public frmLoading()
        {
            InitializeComponent();

            //check if bg worker is null
            if (backgroundWorker == null)
            {
                backgroundWorker = new BackgroundWorker();

                backgroundWorker.DoWork += backgroundWorker_DoWork;
                backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;

                
            }

            backgroundWorker.WorkerReportsProgress = true;

            //start
            backgroundWorker.RunWorkerAsync();
        }

backgroundWorker_DoWork:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 1; i <= 100; i++)
            {
                Thread.Sleep(100);
                backgroundWorker.ReportProgress(i);
            }
        }

backgroundWorker_ProgressChanged:

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //update value of progress bar
            progressBar1.Value = e.ProgressPercentage;
            //set the text of the progress bar
            this.Text = e.ProgressPercentage.ToString();
        }
Paul Alexander
  • 2,686
  • 4
  • 33
  • 69
  • 3
    Use the debugger, Debug > Windows > Threads, and observe what the main thread is doing. It has to be idle, executing inside Application.Run() to get this event handler to execute. Never let it execute expensive code, that's the job of a worker thread. – Hans Passant Sep 16 '20 at 08:26
  • 2
    BGW is obsolete since 2012, completely replaced by Task.Run and Progress. To update the UI periodically though, all you need is [a Timer](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.timer?view=netcore-3.1), not a background thread. Create a simple Winforms timer, enable it on load and disable it once you're done, or when the ProgressBar reaches its maximum – Panagiotis Kanavos Sep 16 '20 at 08:33
  • Thanks, I'll have a look into Task.Run. I think the work needs to be on a separate thread as I've already got large process working in the background on another form. – Paul Alexander Sep 16 '20 at 08:56
  • 1
    @PaulAlexander - `Task.Run` will execute on another thread. – Enigmativity Sep 16 '20 at 11:22
  • Why are you checking whether `backgroundWorker == null`? It's of course `null`, you're in the Form's Constructor. Unless there's something else going on there that you're not showing, like trying to *recycle* this Form somehow. Move `backgroundWorker.RunWorkerAsync();` to `Form.Load` or `Form.OnLoad` (or `OnShown()` to see whether the Form shows rendered). If it doesn't start, then you're not letting it start because something else is blocking the UI Thread so this line of code is never executed. – Jimi Sep 16 '20 at 12:15

1 Answers1

0

Here's how you would do this with Progress<int> and Task.Run:

public frmLoading()
{
    InitializeComponent();

    IProgress<int> progress = new Progress<int>(p =>
    {
        //update value of progress bar
        progressBar1.Value = p;
        //set the text of the progress bar
        this.Text = p.ToString();
    });

    Task.Run(async () =>
    {
        for (int i = 1; i <= 100; i++)
        {
            await Task.Delay(TimeSpan.FromSeconds(0.1));
            progress.Report(i);
        }
    });
}

Personally I prefer Microsoft's Reactive Framework:

public frmLoading()
{
    InitializeComponent();

    Observable
        .Interval(TimeSpan.FromSeconds(0.1))
        .Take(100)
        .ObserveOn(this)
        .Select(p => p + 1)
        .Subscribe(p =>
        {
            //update value of progress bar
            progressBar1.Value = p;
            //set the text of the progress bar
            this.Text = p.ToString();
        });
}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172