As I mentioned in my
To make the life in the multithreaded world easier 1, I kept writing code as below to check the "InvokeRequired" property to check if the method is invoked from a worker thread or the main thread.
private void DoSomethingFunction()
{
if(this.InvokeRequired)
{
this.BeginInvoke((System.Threading.ThreadStart)delegate()
{
DoSomethingFunction();
});
return;
}
// Do something here
}
After doing the check again and again, I started to ask myself - is there a way to abstract it a bit so that I don't need to repeat myself?
And this is what I come up with - a class acts as a smart agent:
Public class AsyncCall
{
public static void AutoBeginInvoke(System.Windows.Forms.Control targetControl, Delegate targetMethod)
{
if (targetControl.InvokeRequired)
targetControl.BeginInvoke(targetMethod);
else
targetMethod.DynamicInvoke(null);
}
}
This method checks to see if this method is invoked from a worker thread or from the main thread where the windows control is created, and invoke the method accordingly.
Our DoSomethingFunction() can be rewritten as:
private void DoSomethingFunction()
{
AsyncCall.AutoBeginInvoke(this, (System.Threading.ThreadStart)delegate(){// Do something here});
}
Let's have a more concrete example, say I want to update a textbox or a label in a thread safe way, in the past, I have to do things like this:
private void UpdateTextBox()
{
if(textBox1.InvokeRequired)
{
textBox1.BeginInvoke((System.Threading.ThreadStart)delegate()
{
UpdateTextBox();
});
return;
}
textBox1.Text = "Update test";
}
private void UpdateLabel()
{
if(lbl1.InvokeRequired)
{
lbl1.BeginInvoke((System.Threading.ThreadStart)delegate()
{
UpdateLabel();
});
return;
}
lbl1.Text = "Update test";
}
Now I simply call:
private void UpdateTextBox()
{
AsyncCall.AutoBeginInvoke(textBox1, (System.Threading.ThreadStart)delegate(){textBox1.Text = "Update test"});
}
private void UpdateLabel()
{
AsyncCall.AutoBeginInvoke(lbl1, (System.Threading.ThreadStart)delegate(){lbl1.Text = "Update test"});
}
Some people may want to separate the anonymous part
(System.Threading.ThreadStart)delegate(){ //do update}
into a different method.But I found it quite nice and neat here.
What if I want to pass parameters to my update method? Then some delegate accepting parameters have to be created.
You can have a delegate defined as this:
public delegate void SomeDelegate(string args);
Then add a new method in AsyncCall class:
public static void AutoBeginInvoke(System.Windows.Forms.Control targetControl, SomeDelegate targetMethod, string args)
{
if (targetControl.InvokeRequired)
targetControl.BeginInvoke(targetMethod, args);
else
targetMethod.DynamicInvoke(args);
}
This is your new UpdateTextBox method:
private void UpdateTextBox()
{
AsyncCall.AutoBeginInvoke(textBox1, (SomeDelegate)delegate(string args){textBox1.Text = args;}, "update test");
}
What if I want to do a search, and after getting the search result back I want to do something else.
Normally, we would have:
public ILIst delegate SomeSearchDelegate();
private IList Search()
{
IList result = null;
// Do search here...
return result;
}
private void OnSearchCompleted(IAsyncResult ar)
{
SomeSearchDelegate del = ar.AsyncState as SomeSearchDelegate;
IList result = del.EndInvoke(ar);
// Do some post search processing...
}
private void SomeSearchMethod()
{
SomeSearchDelegate del = new SomeSearchDelegate(Search);
del.BeginInvoke(OnSearchCompleted, del);
}
To do the task using AsyncCall class, we can define another method in the AsyncCall class:
public static void AutoBeginInvoke(SomeSearchDelegate targetMethod, AsyncCallback callbackMethod)
{
targetMethod.BeginInvoke(callbackMethod, targetMethod);
}
So the SomeSearchMethod() can be rewritten as:
private void SomeSearchMethod()
{
AsyncCall.AutoBeginInvoke(
(SomeSearchDelegate)delegate()
{
IList result = null;
// Do search here...
return result;
},
(AsyncCallback)delegate(IAsyncResult ar)
{
SomeSearchDelegate del = ar.AsyncState as SomeSearchDelegate;
IList result = del.EndInvoke(ar);
// Do some post search processing...
});
}
Hope what discussed above is not as clear as mud to the readers ;)...