Saturday, September 19, 2009

Asynchronous Event Handling

Asynchronous Event handling
Why need Async Event Handling?
Let’s consider an example that you need some data in your application. So you call a method GetData(…) and it will give you the data. But untill you get the data your UI Thread is blocked. So you need something like that you call the method GetData(…) and return, and when data is done an event is raised to the UI that OK I am done and you process the data.
So here are the simple steps for Asynchronous event handling:
Suppose that I had a class “Myclass” which contains a mehod “GetDatawhich I want to call asynchronously, So that it raise an event when it get all the data without blocking main thread.
Step 1: Create MyEventArgs.cs
First decide what you parameters are needed after Get Data Return. These are the properties in MyEventArgs class. Suppose that we need a UserState, Result, and if any exception occurs then Error. So my class will look like this:
public class MyEventArgs
{
public object Result { get; set; }
public Exception Error { get; set; }
public object UserState { get; set; }
}
Above the class I define a delegate eventhandler like this:
public delegate void MyEventHandler(object sender, MyEventArgs e);
Step 2: Create MyEventController.cs
For asynchronous handling we create a delegate for the method. It has the same parameters as in Myclass’ s GetData method. If the GetData has some out parameters then we can also use them. If not then no need to define out parameter.:
public delegate object MyEventDelegate(string param1,out Exception Excep);
Now define a controller class like this:
public class MyEventController
{
public event MyEventHandler MyEventComplete;
MyEventDelegate _MyEventDelegate;
MyClass myClass;
public MyEventController()
{
myClass = new MyClass ();
_ MyEventDelegate = new MyEventDelegate(MyMethod);
}
private void OnMyEventComplete(MyEventArgs e)
{
if(MyEventComplete !=null)
{
MyEventComplete(this,e);
}
}
public void GetData(string param1, object UserState)
{
Exception Excep = null;
object[] _AsyncUserStats = new object[1];
_AsyncUserStats[0] = UserState;
_MyEventDelegate.BeginInvoke(param1, out Excep, new AsyncCallback(MyMethodCallBack), _AsyncUserStats);
}
private object MyMethod(string param1, out Exception exception)
{
return myClass.GetData(param1,out exception);
}
private void MyMethodCallBack(IAsyncResult ar)
{
Exception Excep = null;
AsyncResult aresult = (AsyncResult)ar;
object Result = ((MyEventDelegate)aresult.AsyncDelegate ).EndInvoke(out Excep, ar);
object[] _AsyncUserState = ar.AsyncState as object[];
MyEventArgs result = new MyEventArgs()
{
Error=Excep,
Result =Result,
UserState = _AsyncUserState[0],
};
OnMyEventComplete(result);
}
}
Let’s see what happens in the controller class. It define an event MyEventComplete which will be raised when GetData complete. For this we define a function “OnMyEventComplete” which raise the event when we get all the data. It also defines an object of the delgate we define above “MyEventDelegate”. In the constructer we register the method (MyMethod here) with the delegate which we want to call. In this method we actually call the GetData of MyClass.
Now look at the GetData of MyController class. This is the method which we call when we want to get the data. In this method we call the BeginInvoke of the delegate. In the BeginInvoke it accepts the same parametrs as in the GetData metod of MyClass and two extra parameters of type AsyncCallback and object or object[]. The AsyncCallback contains the method which will be called when it gets the data. The syntax for implementation of this callback method is :
private void MyMethodCallBack(IAsyncResult ar)
And in the MyMethodCallBack we get the result and raise the event by calling OnMyEventComplete method.
So the flow is like this:
clip_image002

In the UI we create a class of the controller and call the GetData of controller. Event “MyEventComplete” will be raised when get Data complete. Before calling the method you have to register the event like this :
MyEventController _myController= new MyEventController();
_myController.MyEventComplete += new MyEventHandler (myController_MyEventComplete);
void myController_MyEventComplete(object sender, MyEventArgs e)
{
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)(() =>
{
/////.. event is raised and we get the result in the e.Result
}));
}
Since this event complete is returned in another thread we neet to use Dispatcher like above.
And when we need the data we use _myController.GetData(….);