May 19, 2009

Threading: Modal Progress Dialog and BackgroundWorker Thread in C#.Net

While working with threads, one should be careful about UI Elements. Specially when we are working with BackgroundWorker thread. Here is an example which shows how to show a modal dialog from thread for displaying progress.

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        BackgroundWorker worker;
        Form2 frm;
        private void button1_Click(object sender, EventArgs e)
        {
            frm = new Form2();
            worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.RunWorkerAsync();     
            frm.ShowDialog();
      
        }
        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            frm.ProgressValue = e.ProgressPercentage;
        }
        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            frm.Close();
            MessageBox.Show("Done");
        }
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            CountTheTime();      
        }
   
        private void CountTheTime()
        {
            int initialValue = 100;
            for (int count = 0; count < initialValue; count = count + 2)
            {
                Thread.Sleep(1000);
                worker.ReportProgress(count);
            }
        }
    }
In this example, I have simply created two windows forms. The first form [Form1] has one button [button1]. button1 will show create a BackgroundWorker thread and launch it asynchronously. It uses method RunWorkerAsync of BackgroundWorker thread instance for this purpose

BackgroundWorker has three main events

  • DoWork - will be fired when we launch the thread.
  • RunWorkerCompleted - will fire when thread completes
  • ProgressChanged - will fire when thread reports progress

and important property

  • WorkerReportsProgress – should be set to True to enable progress reporting from a thread.

related method

  • ReportProgress() – Reports progress back to the calling thread.

In aforementioned code, When we fire DoWork event by calling RunWorkerAsync method on worker thread. Eventhandler for this event will call the method CountTheTime() on the form.

CountTheTime() method intentionally put delay of 1 second. Here you can implement your time consuming code. We call ReportProgress() method on the thread to pass progress from this background thread to the main UI thread which holds our progress bar. This method will fire ProgressChanged Event

  public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }
        public int ProgressValue
        {
            get { return progressBar1.Value ; }
            set { progressBar1.Value  = value; }
        }
    }
Then ProgressChanged eventhandler, worker_ProgressChanged updates the progressbar on Form2 with the help of ProgressValue property.

Conclusion:
Simple example of modal Progressbar with BackgroundWorker thread.

7 comments:

  1. Hi,

    But my situation is different: What if I want to display the value of your int Count from CountTheTime()
    in frm?

    Benj

    ReplyDelete
  2. @Nunez, in worker_ProgressChanged event, we are already getting the value of count from e.ProgressPercentage. You can assign that value to your display control on the form.

    ReplyDelete
  3. Thanks for an amazing tutorial, you rock!

    ReplyDelete
  4. Hi,
    I am getting Exception on (worker.ReportProgress(count);).....
    "This BackgroundWorker states that it doesn't report progress. Modify WorkerReportsProgress to state that it does report progress.

    ReplyDelete
  5. @Ashu, Exception message is self explanatory. Please state it as below:

    worker.WorkerReportsProgress = true;

    if you haven't already done so.

    ReplyDelete
  6. Simple, elegant, and clear. Best resource I found on the subject.

    ReplyDelete
  7. The Kettic Status Strip control is able to add progress bar to show state and operation progress.

    ReplyDelete