65.9K
CodeProject is changing. Read more.
Home

Asynchronous method calling using events and delegates

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (8 votes)

Mar 31, 2012

CPOL

3 min read

viewsIcon

42516

downloadIcon

1387

This article describes how to call methods asynchronously using delegates and custom events.

Sample Image

Introduction

In this article, we’ll elaborate how to call methods asynchronously. As we all know, delegates are used to call methods asynchronously, but here we’ll combine asynchronous function calling and the event handling concept for achieving Asynchronous Processing. To avoid confusion, let’s define what we are going to do in this example shortly.

  1. We’ll develop a Task class that contains an IterateFile() method and three events – StatusEvent, Complete, ProgressChanged. StatusEvent will keep track of the file status during file processing. The Complete event is raised when file processing completes. The ProgressChanged event is raised when the iteration completes.
  2. We’ll also develop the FileProcessing class that contains the Processing() method and StatusEvent. StatusEvent is raised when file processing status changes.
  3. We’ll have a Windows Form that displays all this information.

Objective

Achieving asynchronous behavior for our function calling using delegates and event handlers.

Using the code

We first develop the TaskToPerform class with the IterateFile method and events. So here is our class:

class TaskToPerform
{
    public event StatusEventHandler StatusEvent
    {
        add
        {
            statusEvent += value;
        }
        remove
        {
            statusEvent -= value;
        }
    }
    private StatusEventHandler statusEvent;

    public event CompletedEventHandler Complete
    {
        add
        {
            complete += value;
        }
        remove
        {
            complete -= value;
        }
    }
    private CompletedEventHandler complete;

    public event ProgressValueChangedEventHandler ProgressValueChanged
    {
        add
        {
            progressValueChange += value;
        }
        remove
        {
            progressValueChange -= value;
        }
    }
    private ProgressValueChangedEventHandler progressValueChange;

    public void IterateFile(string path)
    {
        string[] files = System.IO.Directory.GetFiles(path, "*.*");
        int tot = files.Length;
        int cnt = 1;

        var enumerator = files.GetEnumerator();

        while (enumerator.MoveNext())
        {
            FileProcessing fp = new FileProcessing(enumerator.Current.ToString());
		fp.StatusEvent+= new StatusEventHandler(This_StatusEvent);
            fp.Processing();

            if (progressValueChange != null)
                progressValueChange(this, 
                  new ProgressValueChangeEventArgs() 
                  { MaxValue = tot, MinValue = 0, Value = cnt++ });
        }

        if (complete != null)
            complete(this);
    }

    public void This_StatusEvent(object sender, StatusEventArgs e)
    {
        if (statusEvent != null)
            statusEvent(sender, e);
    }
}

As we discussed we’ve a class with three events. One new thing that might surprise you is event declaration.

public event ProgressValueChangedEventHandler ProgressValueChanged
{
    add
    {
        progressValueChange += value;
    }
    remove
    {
        progressValueChange -= value;
    }
}
private ProgressValueChangedEventHandler progressValueChange;

Yes, we can define our events like properties also as shown above. This kind of declaration is known as custom event declaration. Now we come to the main part of the discussion – the IterateFile method.

public void IterateFile(string path)
{
    string[] files = System.IO.Directory.GetFiles(path, "*.*");
    int tot = files.Length;
    int cnt = 1;

    var enumerator = files.GetEnumerator();

    while (enumerator.MoveNext())
    {
        FileProcessing fp = new FileProcessing(enumerator.Current.ToString());
        fp.StatusEvent+= new StatusEventHandler(This_StatusEvent);
        fp.Processing();

        if (progressValueChange != null)
            progressValueChange(this, 
              new ProgressValueChangeEventArgs() { MaxValue = tot, MinValue = 0, Value = cnt++ });
    }

    if (complete != null)
        complete(this);
}

In this method, we fetch all files from a given path and iterate over that collection. Here we do something tricky that I define the FileProcessing class object and pass the file name as argument in the FileProcessing class’ constructor. Then register its StatusEvent with a method defined in our task class. That means we’ve event handler code for the FileProcessing StatusEvent in our TaskToPerform class. So whenever StatusEvent is invoked from the FileProcessing class it is handled in the TaskToPerform class. The ProgressValueChange event will fire after processing is  completed for each file so that from that event we could get an idea about how many files completed processing. After all files complete their processing, the Complete event is fired that indicates completion of the task.

Let’s move to our second point of discussion that is the FileProcessing class which is shown below:

class FileProcessing
{
    private readonly string filename;

    public event StatusEventHandler StatusEvent
    {
        add
        {
            statusEvent += value;
        }
        remove
        {
            statusEvent -= value;
        }
    }
    private StatusEventHandler statusEvent;

    public FileProcessing(string fileName) { this.filename = fileName; }

    public void Processing()
    {
        System.Threading.Thread.Sleep(500);
        if (statusEvent != null)
        {
            var args = new StatusEventArgs() { Name = filename, Status="Opened" };
            statusEvent(this, args);
            System.Threading.Thread.Sleep(500);
            args.Status = "Processed";
            statusEvent(this, args);
            System.Threading.Thread.Sleep(1000);
            args.Status = "Closed";
            statusEvent(this, args);
            System.Threading.Thread.Sleep(500);
        }
    }
}

As you can see, in this class, we’ve a Processing method which fires the Status event periodically. So ultimately we’ll have different states for a single file periodically. I think there is no more description needed for this class. Finally we are moving to our main part that is on the WinForm. On the WinForm I’ve put a progressbar and two labels. lblStatus will show Filestatus which is updated during file processing. The progress bar works on the ProgressValueChanges event. Let’s see the logic:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    void UpdateLabelStatus(Label lbl, string message)
    {
        if (lbl.InvokeRequired)
        {
            lbl.BeginInvoke(new ActionLabel, string>(UpdateLabelStatus), lbl, message);
        }
        else
        {
            lbl.Text = message;
            lbl.Update();
            lbl.Parent.Update();
        }
    }

    void UpdateProgressBar(ProgressBar pBar, int maxValue, int value)
    {
        if (pBar.InvokeRequired)
        {
            pBar.BeginInvoke(new Action<ProgressBar, int, int>(
                             UpdateProgressBar), pBar, maxValue, value);
        }
        else
        {
            pBar.Maximum = maxValue;
            pBar.Minimum = 0;
            pBar.Value = value;
            pBar.Update();
            pBar.Parent.Update();

            string pervalue = string.Format("{0} file(s) processed out of {1}", value, maxValue);
            UpdateLabelStatus(lblProgress, pervalue.ToString());
        }
    }

    void MyEventFunction(object sender, StatusEventArgs e)
    {
        UpdateLabelStatus(lblStatus, string.Format("File {0} {1} successfully", e.Name, e.Status));
    }

    void EventDemo_ProgressValueChanged(object sender, ProgressValueChangeEventArgs e)
    {
        UpdateProgressBar(pBar, e.MaxValue, e.Value);
    }

    void EventDemo_Complete(object sender)
    {
        UpdateLabelStatus(lblStatus, "NA");
        UpdateLabelStatus(lblProgress, "NA");
    }

    private void Form1_Load(object sender, EventArgs e)
    {  }

    void InitiateProcess()
    {
        TaskToPerform ed = new TaskToPerform();
        ed.StatusEvent += new StatusEventHandler(MyEventFunction);
        ed.Complete += new CompletedEventHandler(EventDemo_Complete);
        ed.ProgressValueChanged += 
            new ProgressValueChangedEventHandler(EventDemo_ProgressValueChanged);
        ed.IterateFile(@"C:\Windows");
    }

    private void btnStart_Click(object sender, EventArgs e)
    {
        System.Threading.Thread t = new System.Threading.Thread(InitiateProcess);
        t.Start();
    }
}

In this form, you’ll see that I used the Action<> delegate to call the method asynchronously.

void UpdateLabelStatus(Label lbl, string message)
{
    if (lbl.InvokeRequired)
    {
        lbl.BeginInvoke(new Action<Label, string>(UpdateLabelStatus), lbl, message);
    }
    else
    {
        lbl.Text = message;
        lbl.Update();
        lbl.Parent.Update();
    }
}

In the UpdateLabelStatus method, we pass the Label object that is to be changed and the message string passed as arguments. We invoke this method asynchronously using the Action<> delegate. Thus we change the label value asynchronously and hence for the Progressbar also.

Conclusion

I hope this article has helped you understand asynchronous processing thoroughly, but still as a developer I advise you all to develop more examples to understand this concept thoroughly.