Kashif
Kashif

Reputation: 875

Backgroundworker ProgressChanged acts after the worker is done

I've created a form to pop up and display a progress bar whenever I call one of my time-consuming routines. I feed the progress of my routine through the UpdateProgress method.

I'm using a background worker to allow the user to move the form around and keep doing their business while this form updates. However, the form just locks up until the routine is complete, then quickly ramps the progress bar to 100% and quits (as it should). The progress bar should, imo, update alongside the progress of the calls being made to the UpdateProgress method.

What am I doing wrong here?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace myNameSpace
{
    public partial class ProgressIndicator : Form
    {
        int progressPercentage;

        public ProgressIndicator()
        {
            InitializeComponent();
        }

        void progressUpdater_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // update the UI with appropriate fields
            progressBar.Value = e.ProgressPercentage;
            labelCommunicating.Text = "In progress: " + e.ProgressPercentage + "% complete";
        }

        void progressUpdater_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.Close();
        }

        void progressUpdater_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            while (true)
            {
                if (progressPercentage >= 100)
                {
                    break;
                }

                worker.ReportProgress(progressPercentage);

                Thread.Sleep(100);
            }
        }

        public void UpdateProgress(int progressPercentage)
        {
            this.progressPercentage = progressPercentage;
        }

        private void ProgressIndicator_Load(object sender, EventArgs e)
        {
            BackgroundWorker progressUpdater = new BackgroundWorker();
            progressUpdater.WorkerReportsProgress = true;
            progressUpdater.WorkerSupportsCancellation = true;
            progressUpdater.DoWork += new DoWorkEventHandler(progressUpdater_DoWork);
            progressUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler(progressUpdater_RunWorkerCompleted);
            progressUpdater.ProgressChanged += new ProgressChangedEventHandler(progressUpdater_ProgressChanged);

            progressUpdater.RunWorkerAsync();
        }
    }
}

Upvotes: 0

Views: 3181

Answers (2)

Sorceri
Sorceri

Reputation: 476

You can create the process in this fashion that way you do not need to wrap your call around the Invoke method.

//delegate method
private delegate void updateProgressDelegate(int progress);

//actual method
private void updateProgress(int progress)
{
    if(this.InvokeRequired)
    {
        this.Invoke(new updateProgressDelegate(updateProgress), progress);
    }
    else
    {
        progressBar.value = progress;
    }
}

Upvotes: 0

Chibueze Opata
Chibueze Opata

Reputation: 10054

This smells like a far-fetched solution and I think your problem lies with the while loop. However, a better approach may be to simply update your ProgressBar without blocking the UI by using Invoke(); e.g.

Invoke(new myUpdate(updateProgress), pval);//call invoke whenever you need to update the progress bar assuming pval is an integer with the value to update with. This could be in a thread for instance.

//declare this as a class level delegate
private delegate void myUpdate(int progress);

//method to update progress bar
private void updateProgress(int progress)
{
    progressBar.Value = progress;
}

Upvotes: 1

Related Questions