This is the trick to be used in order invoke some piece of code in main UI thread after some delay without going through the BeginInvoke() stuff everytime. A possible use case is where an operation regarding an external device is performed and its status must be checked after some time. If device does not operate as requested or it does not respond at all, UI thread can show warning messages to inform the operator. Since warning messages will be shown in the UI thread, it is important that the delayed code is executed in the UI thread as well.
Timers and BeginInvoke with delegates can be used here as well but they make the code harder to follow in the case of many events and delegates.
Following class wraps up the delayed processing operations. It has a static method
which can be called from any thread. BackgroundWorker's RunWorkerCompleted method is used to execute the code later in the UI thread. Since the callback is executed in the UI thread, all operations on the UI control can be performed.
public class DelayedAction
{
public static void Do(int timeout, MethodInvoker callback)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(DoWork);
worker.RunWorkerCompleted += new WorkerCompleted(RunWorkerCompleted);
worker.RunWorkerAsync(new object[] { timeout, callback});
}
static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MethodInvoker callback = (MethodInvoker)e.Result;
callback.Invoke();
}
static void DoWork(object sender, DoWorkEventArgs e)
{
object[] args = (object[])e.Argument;
Thread.Sleep((int)args[0]);
e.Result = args[1];
}
}
After that we can easily use that class in our main UI thread as follows where we can easily track the business logic.
...
label1.Text = "Powering on device";
device.PowerOn();
DelayedAction.Do(10000, (MethodInvoker)delegate()
{
if( device.IsPowered() == false )
{
label1.Text = "Device operation failed";
}
else
{
label1.Text = "Device OK.";
}
});
...