Click here to Skip to main content
15,878,852 members
Articles / Programming Languages / C#

Asynchronous method calling using events and delegates

Rate me:
Please Sign up or sign in to vote.
4.58/5 (8 votes)
15 Mar 2013CPOL3 min read 41.7K   1.4K   42   7
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:

C#
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.

C#
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.

C#
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:

C#
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:

C#
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.

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader Automation Anywhere Inc.
India India
I am Himanshu Manjarawala, Garduate in Computer Science and MCA From Veer Narmad South Gujarat University, Surat Gijarat India. Currently working as Sr. Software Developer in Automation Anywhere Softwares Pvt. Ltd. Vadodara, Gujarat

Comments and Discussions

 
Questiondumb... overly complex (and scary) implementation Pin
Michael Kosak11-Jun-18 6:24
Michael Kosak11-Jun-18 6:24 
QuestionIs it the best approach? Pin
Philippe Mori18-Mar-15 6:15
Philippe Mori18-Mar-15 6:15 
SuggestionSimplify the event declarations Pin
Pascal-783-Feb-14 3:57
professionalPascal-783-Feb-14 3:57 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun15-Mar-13 1:22
Humayun Kabir Mamun15-Mar-13 1:22 
QuestionDo you have a vb.net version Pin
Mark Regal7-Nov-12 15:29
Mark Regal7-Nov-12 15:29 
This works pretty well but the threading in vb seems more simplified. Is there any chance that you could post a vb.net version? That would be awesome...
AnswerRe: Do you have a vb.net version Pin
Himanshu Manjarawala14-Mar-13 23:40
Himanshu Manjarawala14-Mar-13 23:40 
GeneralMy vote For This Pin
Anurag Sarkar31-Mar-12 22:34
Anurag Sarkar31-Mar-12 22:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.