private void DoSomethingFunction()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?
{
if(this.InvokeRequired)
{
this.BeginInvoke((System.Threading.ThreadStart)delegate()
{
DoSomethingFunction();
});
return;
}
// Do something here
}
And this is what I come up with - a class acts as a smart agent:
Public class AsyncCallThis 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.
{
public static void AutoBeginInvoke(System.Windows.Forms.Control targetControl, Delegate targetMethod)
{
if (targetControl.InvokeRequired)
targetControl.BeginInvoke(targetMethod);
else
targetMethod.DynamicInvoke(null);
}
}
Our DoSomethingFunction() can be rewritten as:
private void DoSomethingFunction()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:
{
AsyncCall.AutoBeginInvoke(this, (System.Threading.ThreadStart)delegate(){// Do something here});
}
private void UpdateTextBox()Now I simply call:
{
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";
}
private void UpdateTextBox()Some people may want to separate the anonymous part
{
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"});
}
(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)This is your new UpdateTextBox method:
{
if (targetControl.InvokeRequired)
targetControl.BeginInvoke(targetMethod, args);
else
targetMethod.DynamicInvoke(args);
}
private void UpdateTextBox()What if I want to do a search, and after getting the search result back I want to do something else.
{
AsyncCall.AutoBeginInvoke(textBox1, (SomeDelegate)delegate(string args){textBox1.Text = args;}, "update test");
}
Normally, we would have:
public ILIst delegate SomeSearchDelegate();To do the task using AsyncCall class, we can define another method in the AsyncCall class:
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);
}
public static void AutoBeginInvoke(SomeSearchDelegate targetMethod, AsyncCallback callbackMethod)So the SomeSearchMethod() can be rewritten as:
{
targetMethod.BeginInvoke(callbackMethod, targetMethod);
}
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 ;)...
No comments:
Post a Comment