Showing posts with label Delegates. Show all posts
Showing posts with label Delegates. Show all posts

Saturday, 21 April 2012

Asynchronous methods in C#: Part II


Introduction
In this article we demonstrate how to report progress information and intermediate results from asynchronous method. This article builds on previous article, Asynchronousmethod in C#: Part I.

Using Code
In this article we do following changes in our previous example.

  • ·         Modify Perform method for reporting progress.
  • ·         Implement ProgressChanged event.
  • ·         Define method ReportProgrss that synchronizes Perform method and ProgressChanged event

Perform Method:
Here is a perform method that we define in our previous example.
        private void Perform(string[] files)
        {
            foreach (string file in files)
            {
                //do something......
                Thread.Sleep(100);
            }
        }
Now we modify it such way, that it reports progress of task to client code and processed files.
        private void Perform(string[] files)
        {
            int counter = 0;
            foreach (string file in files)
            {
                //do something......
                Thread.Sleep(100);

                counter++;
                int percentage = (100 * counter) / files.Length;

                ReportProgress(percentage, file);
            }
        }
After processing file, we compute percentage in percentage and paases it as an argument in ReportProgress() method, which is an example of how to pass intermediate result to client code.

ProgressChanged event:

This event raised whenever asynchronous method wants to report progress to client code.

        public event ProgressChangedEventHandler ProgressChanged
        {
            add
            {
                this.progressChangedEventHandler += value;
            }
            remove
            {
                this.progressChangedEventHandler -= value;
            }
        }
        private ProgressChangedEventHandler progressChangedEventHandler;

        protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
        {
            if (progressChangedEventHandler != null)
                progressChangedEventHandler(this, e);
        }

Handling ProgressChanged event in client code:

Register and implement handler of ProgressChanged event.

        t.ProgressChanged += new ProgressChangedEventHandler(task_ProgressChange);

        static void task_ProgressChange(object sender, ProgressChangedEventArgs e)
        {
            System.Diagnostics.Debug.Print("[Task] Progress: {0} %, Current File: {1}", e.ProgressPercentage, e.UserState);
        }

ReportProgress method:

This method calls ProgressChanged event through AsyncOperation object.

        void ReportProgress(int percentProgress, object userState)
        {
            // FIXME: verify the expected behavior
            if (!IsBusy)
                return;

            async.Post(delegate(object o)
            {
                ProgressChangedEventArgs e = o as ProgressChangedEventArgs;
                OnProgressChanged(e);
            },
                new ProgressChangedEventArgs(percentProgress, userState));
        }


In this series
  1.  Asynchronous method in C#: Part - I 
  2. Asynchronous method in C#: Part - II.

Asynchronous method in C# - Part I


Introduction
In this article, we’ll demonstrate how to write asynchronous method. For better understanding first we’ll perform task conventionally and after that we’ll create its Async version.
Objective
To write Asynchronous method.
Using the code
Let first design class say Task and write a Perform() method that iterate loops over some collection.
    class Task
    {
        private void Perform(string[] files)
        {
            foreach (string file in files)
            {
                //do something......
                Thread.Sleep(100);
            }
        }
    }
See above example in which we are iterating loop for array of string. This is convention method which we all normaly write.
Now, let’s try to perform same task asynchronously using delegates. For this we need following member:
  • Perform() method – does actual work.
  • PerformAsync() method – invokes the asynchronous operation.
  • IsBusy property – indicates that asynchronous operation is going on.
  • CompleteTask() method – called when perform method completed operation.
  • TaskCompleted event – notifies of the asynchronous operation completion.

Perform() Method:
This method executes in background and does actual task. In our example it iterates loop over array of string.
        private void Perform(string[] files)
        {
            foreach (string file in files)
            {
                //do something......
                Thread.Sleep(100);
            }
        }

        delegate void TaskEventHandler(string[] files, AsyncOperation async, SendOrPostCallback callback);

PerformAsync() Method:

This method invokes asynchronous operation and returns immediately. If asynchronous operation is running then throw an exception.

        public void PerformAsync(string[] files)
        {
            if (IsBusy)
                throw new InvalidOperationException("The background worker is busy.");

            async = AsyncOperationManager.CreateOperation(this);

            TaskEventHandler handler =
                new TaskEventHandler(ProcessWorker);
            handler.BeginInvoke(files, async, CompleteWorker, null, null);
        }

First it checks for busy status of operation, if it’s so then throw InvalidCastOperationException.
Next an AsyncOperation is created. This object is used by worker thread to invoke client’s event handler on proper thread.
Next TaskEventHandler is registered with proper handler method. Through TaskEventHandler, we can invoke our Task asynchronously.
Now, the asynchronous operation is started in separate thread using handler.BeginInvoker method. BeginInvoke method contains two more parameter along with string array.
  1. A delegate of type SendOrPostCallback to a callback method which called when operation finishes.
  2. A custom object that is stored in the AsyncState property of  an IAsyncResult instance return by BeginInvoke method.

CompleteTask Method:

This method calls when worker invoker has finishes it’s processes.
        void CompleteTask(object state)
        {
            object[] args = (object[])state;
            RunWorkerCompletedEventArgs e =
                args[0] as RunWorkerCompletedEventArgs;
            AsyncOperation async = args[1] as AsyncOperation;

            SendOrPostCallback callback = delegate(object darg)
            {
                OnRunWorkerCompleted(darg as RunWorkerCompletedEventArgs);
            };

            async.PostOperationCompleted(callback, e);

            this.async = null;
        }

First the AsyncOperation object is obtained and at last TaskCompleted event fired through AsyncOperation object

TaskCompleted Event:
This event fired when the asynchronous operation completed.

        public event RunWorkerCompletedEventHandler TaskCompleted
        {
            add
            {
                this.taskCompletedEventHandler += value;
            }
            remove
            {
                this.taskCompletedEventHandler -= value;
            }
        }
        private RunWorkerCompletedEventHandler taskCompletedEventHandler;

        protected virtual void OnTaskCompleted(RunWorkerCompletedEventArgs e)
        {
            if (taskCompletedEventHandler != null)
                taskCompletedEventHandler(this, e);
        }

In this Series
  1. Asynchronous method in C# - Part I
  2. Asynchronous method in C# - Part II

Wednesday, 11 January 2012

Asynchronous Processing

Introduction
                        Hi, today we will demonstrate asynchronous processing using delegates and events. One might think what the need of doing work   asynchronously in windows environment. Yes, it is required. By sample example we will prove this.
The Program
                        In this program we will develop a class will have certain events and delegates to handle those events. Our class will have a function to perform task and continuously changes the status through raising events.
public class Task
    {
        public delegate void UpdateStatusEventHandler(string text, int total, int current);
        public delegate void UpdateTextEventHandler(string text);
        public delegate void UpdateProgressBarEventHandler(int total, int value);

        public event UpdateStatusEventHandler UpdateStatus;
        public event UpdateTextEventHandler UpdateText;
        public event UpdateProgressBarEventHandler UpdateProgressBar;

        ……….
    }
                As shown in code we define 3 events for updating status, text and progress bar value as per task perform. For handling these events we define 3 delegates. As we all knows delegate works asynchronously, so whenever we raise these events, they will execute asynchronously.
This event handled from Windows Form. Code to handle these events are as follows.
            Task task = new Task();
            task.UpdateProgressBar += new Task.UpdateProgressBarEventHandler(task_UpdateProgressBar);
            task.UpdateStatus += new Task.UpdateStatusEventHandler(task_UpdateStatus);
            task.UpdateText += new Task.UpdateTextEventHandler(task_UpdateText);
in order to handle these events we’ve to register them first. To register them first create instance of class which owns those events. As you can see delegates which we defined in that class are working as event handler and each event handler has reference of a function having code for handling this events.
        private void task_UpdateStatus(string text, int total, int current)
        {
            eUpdateStatus(lblStatus, text, total, current);
        }

        private void task_UpdateText(string text)
        {
            eUpdateText(lblText, text);
        }

        private void task_UpdateProgressBar(int total, int value)
        {
            eUpdateProgressBar(pbTask, total, value);
        }
Now let us see how to update windows contron state asynchronously. For that you have to define delegates. As we knows delegates are special typed class which can point function having same signature. We’ll define delegates and functions that work asynchronouly for us.
        private delegate void delUpdateStatus(Label lbl, string text, int total, int current);       
        private void mUpdateStatus(Label lbl, string text, int total, int current)
        {
            if (lbl.InvokeRequired)
            {
                lbl.BeginInvoke(new delUpdateStatus(mUpdateStatus1), lbl, text, total, current);
            }
        }

        private void mUpdateStatus1(Label lbl, string text, int total, int current)
        {
            lbl.Text = string.Format("{0}/{1}\n {2}", current, total, text);
            lbl.Update();
            lbl.Parent.Update();
            this.Update();
        }
As we shown above we defined delegate and its function for updating label status. Here you notice BeginInvoke method which execute asynchronously for updating control status