Progress Bar Delegate


When I wrote my first commercial application – a program that split XML files – I first created a class called SplitXML that split the file, but I needed to update a Progress Bar control with how much of the file had been split on the form that instantiated the SplitXML class. The following is a generic example of how you achieve this using delegates.

Note: This tutorial is available in both C# and Visual Basic

First create a DoWork Class

Visual Basic

Public Delegate Sub ProgressBarHandler(ByVal min As Integer, ByVal max As Integer, ByVal value As Integer)

 

Public Class DoWork

 

    Public Event ReportProgress As ProgressBarHandler

 

 

    Public Sub DoTheWork()

 

        Dim min As Integer = 0

        Dim max As Integer = 10

 

        For value As Integer = 0 To max – 1

 

            ‘ Simulates a long running process like splitting a file,

            ‘ or getting data from a web service call, by stopping for

            ‘ 1 second (1000 milliseconds) in the loop

 

            RaiseEvent ReportProgress(min, max, value)

            System.Threading.Thread.Sleep(1000)

        Next

 

    End Sub

End Class

C#

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace ProgressBarDelegate

{

    public delegate void ProgressBarHandler(int min, int max, int value);

 

    public class DoWork

    {

        public event ProgressBarHandler ReportProgress;

 

        public void DoTheWork()

        {

            int min = 0;

            int max = 10;

 

            for (int value = 0; value < max; value++)

            {

                // Simulates a long running process like splitting a file,

                // or getting data from a web service call, by stopping for

                // 1 second (1000 milliseconds) in the loop

 

                ReportProgress(min, max, value);

                System.Threading.Thread.Sleep(1000);

 

            }

        }

 

    }

}

In the MainForm drag a button and a progress bar on the form

Form1

Click the button to add an event handler, and add the following code

Visual Basic

Public Class Form1

 

    Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles button1.Click

        Dim doWork As New DoWork()

        AddHandler doWork.ReportProgress, AddressOf doWork_ProgressBarProgress

        doWork.DoTheWork()

    End Sub

 

    Private Sub doWork_ProgressBarProgress(ByVal min As Integer, ByVal max As Integer, ByVal value As Integer)

        progressBar1.Minimum = min

        progressBar1.Maximum = max

        progressBar1.Value = value + 1

 

    End Sub

End Class

C#

using System;

using System.Windows.Forms;

 

namespace ProgressBarDelegate

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            DoWork doWork = new DoWork();

            doWork.ReportProgress += new ProgressBarHandler(doWork_ProgressBarProgress);

            doWork.DoTheWork();

        }

 

        void doWork_ProgressBarProgress(int min, int max, int value)

        {

            progressBar1.Minimum = min;

            progressBar1.Maximum = max;

            progressBar1.Value = value + 1;

 

        }

    }

}

This is quite a common requirement when programming i.e. letting an Form know the progress of a method in an instantiated class. Subsequent need of this functionality has resulted in my implementing this the correct "Windows" way:

Sometimes you need to pass more than one value or reference in the delegate. As a best practice the signature of a delegate is always;

Visual Basic

Public Delegate Sub SomeHandler(ByVal sender As Object, ByVal e As SomeEventArgs)

 

C#

 public delegate void SomeHandler(object sender, SomeEventArgs e);

This means that if you need to pass more than one value (like the first example), this best practice is not adhered to. There is an eloquent way to do this though. I have two classes in the example.

First create a custom EventArgs class that takes two values (you can modify this to take any number of parameters your require)

Visual Basic

   Public Class ProgressBarProgressEventArgs

        Inherits System.EventArgs

        Private m_maximum As Integer

        Private m_stage As Integer

 

        Public Property Maximum() As Integer

            Get

                Return m_maximum

            End Get

            Set(ByVal value As Integer)

                m_maximum = value

            End Set

        End Property

        Public Property Stage() As Integer

            Get

                Return m_stage

            End Get

            Set(ByVal value As Integer)

                m_stage = value

            End Set

        End Property

    End Class

 

C#

 public class ProgressBarProgressEventArgs : System.EventArgs

    {

        private int maximum;

        private int stage;

 

        public int Maximum

        {

            get { return maximum; }

            set { maximum = value; }

        }

        public int Stage

        {

            get { return stage; }

            set { stage = value; }

        }     

    }

Secondly create the DoWork class where the actual works takes place. This could be the splitting of an XML file, a production line in a factory or whatever.

Visual Basic

    Public Delegate Sub ProgressBarHandler(ByVal sender As Object, ByVal e As ProgressBarProgressEventArgs)

 

    Public Class DoWork

        Public Event ReportProgress As ProgressBarHandler

 

        Public Sub DoTheWork()

            For stage As Integer = 1 To 5

 

                OnStageCompleted(stage, 5)

                System.Threading.Thread.Sleep(1000)

            Next

        End Sub

 

        Private Sub OnStageCompleted(ByVal stage As Integer, ByVal max As Integer)

            Dim args As New ProgressBarProgressEventArgs()

            args.Stage = stage

            args.Maximum = max

        RaiseEvent ReportProgress(Me, args)

        End Sub

    End Class

 

C#

 public delegate void ProgressBarHandler(object sender, ProgressBarProgressEventArgs e);

 

    public class DoWork

    {

        public event ProgressBarHandler ReportProgress;

 

        public void DoTheWork()

        {

            for (int stage = 1; stage < 6; stage++)

            {

 

                OnStageCompleted(stage, 5);

                System.Threading.Thread.Sleep(1000);

            }

        }

 

        private void OnStageCompleted(int stage, int max)

        {

            ProgressBarProgressEventArgs args = new ProgressBarProgressEventArgs();

            args.Stage = stage;

            args.Maximum = max;

            ReportProgress(this, args);

        }

 

    }

Finally in the Mainform

Visual Basic

Public Class Form1

 

    Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles button1.Click

        Dim doWork As New DoWork()

        AddHandler doWork.ReportProgress, AddressOf doWork_ReportProgress

        doWork.DoTheWork()

    End Sub

 

    Private Sub doWork_ReportProgress(ByVal sender As Object, ByVal e As ProgressBarProgressEventArgs)

        progressBar1.Maximum = e.Maximum

        progressBar1.Value = e.Stage

    End Sub

 

 

End Class

C#

using System;

using System.Windows.Forms;

 

namespace ProgressBarDelegate

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            DoWork doWork = new DoWork();

            doWork.ReportProgress += new ProgressBarHandler(doWork_ReportProgress);

            doWork.DoTheWork();

        }

 

        void doWork_ReportProgress(object sender, ProgressBarProgressEventArgs e)

        {

            progressBar1.Maximum = e.Maximum;

            progressBar1.Value = e.Stage;

        }

 

    }

}

Try debugging this and you should see that this is much more "sensible", although the first example is much easier to understand. This is the preferred way of declaring delegates.

5 thoughts on “Progress Bar Delegate

  1. nice tutorial could maybe wrote one for updating control from classes

    as example access form 2 to form 1 via a class

  2. Do you have a sample project for Visual Basic by any chance? Part of the most vital parts of understanding delegates is to have a clear picture to work with. The way this tutorial is displayed add more complexity to an already complex piece of coding.

    If your goal is to provide some understanding on how threads work, why make us piece together co-mingled code sources? If it’s not to much trouble, why not split the vb and c# code into an easy to use format where we can transfer your cool knowledge into a working sample?

  3. I have been looking for this code for 2 days and I finally found it!. I now know how to use Delegate (which was an interview question that I got wrong!) Thank you, a very good snippet!!!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s