ProgressEvent

Question: When doing a progressive operation (e.g. a foreach loop), how do you inform user of your progress?

Answer: You raise an Event.

The scope of this page is simply to show you how to create a ProgressEventArgs class and implement it. For further information on delegates and events, I suggest this article.
Email Image
kick it on DotNetKicks.com
The ProgressEventArgs class

"ProgressEventArgs - An EventArgs class that can be used whenever you need to raise an event that contains progress information."

The ProgressEventArgs class is the object that is raised by an event and received by any delegate that is subscribed as an event handler. Once created, you can raise this event from any other class that needs to keep the user informed of the progress of an operation.

The ProgressEventArgs class only requires 3 properties:

  1. The Minimum value
  2. The Maximum value
  3. The Current value
/* The ProgressEventArgs class
All event arguments must inherit from System.EventArgs, so we inherit from that class. */

public class ProgressEventArgs : System.EventArgs
{
    /* We have private properties for each value we are storing. */
    private int minValue;
    private int maxValue;
    private int currentValue;

    /* Since this is a fairly simple class and once set, the properties do not change.
    Therefore, we set all the values when the class is constructed. */

    public ProgressEventArgs(int minValue, int maxValue, int currentValue)
    {
        this.minValue = minValue;
        this.maxValue = maxValue;
        this.currentValue = currentValue;
    }

    public int MinValue
    {
        get { return this.minValue; }
    }

    public int MaxValue
    {
        get { return this.maxValue; }
    }

    public int CurrentValue
    {
        get { return this.currentValue; }
    }
}

The next step is to create an event of type EventHandler<ProgressEventArgs> in a class that raises an event containing progress information.

Consider the following class which has a method that simply counts to 100.

In order for this class to raise ProgressEventArgs, the class needs to have an event of type EventHandler<ProgressEventArgs>. In this class it's called CounterIncreased.

public class Foo
{
    /* This is the event that the CountTo100 method will raise. */
    public event EventHandler<ProgressEventArgs> CounterIncreased;

    /* This method will raise the CounterIncreased event. */
    public void CountTo100()
    {
        /* Loop round incrementing the value of i from 0 to 100. */
        for (int i = 1; i = 100; i++)
        {
            /* Raise a new CounterIncreased event which contains a new ProgressEventArgs
             with the minimum set to 0, the maximum set to 100 and the current value set
             to the value of i. */

            OnCounterIncreased(new ProgressEventArgs(0, 100, i);
        }
    }

    /* This method is called when we want to raise the RecordExported event.
    It checks whether anyone has subscribed to the event before raising it as if no-one has subscribed,
    we would get a NullReferenceException when we try and raise it. */

    protected void OnCounterIncreased(ProgressEventArgs e)
    {
        if (CounterIncreased != null)
            CounterIncreased(this, e);
    }
}

In our application, we simply need to subscribe to this event and create an event handler for it. In this case, we are incrementing a progress bar.

/* In the Form Code, use the following code. */
private void Form1_Load(object sender, EventArgs e)
{
    /* Create an instance of Foo */
    Foo foo = new Foo();

    /* Register an event handler for the CounterIncreased event on the Foo class. */
    foo.CounterIncreased += new EventHandler<ProgressEventArgs>(Foo_CounterIncreased);

    /* Call the method that is going to raise the event. */
    foo.CountTo100();
}

/* Event Handler for Foo.CounterIncreased */
void Foo_CounterIncreased(object sender, ProgressEventArgs e)
{
    /* Set the progress bar values according to the ProgressEventArgs supplied. */
    progressBar1.Minimum = e.MinValue;
    progressBar1.Maximum = e.MaxValue;
    progressBar1.Value = e.CurrentValue;
}

The beauty of this approach is that we are not passing UI elements into business classes, and also it takes minimal effort to implement. The other useful thing is that the object calling your class does not have to subscribe to the event. In the example above, foo.CountTo100() will work exactly the same regardless of whether the caller has subscribed to the CounterIncreased event.


This article was published on the 24th December 2007