Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming

Execute later for delayed action

5.00/5 (1 vote)
12 Aug 2011CPOL1 min read 15.4K  
Code blocks are executed asyncronously in the UI thread after a given timeout.
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.
C#
 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});
   }

   // Notified when our thread terminates
   static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
   {
      MethodInvoker callback = (MethodInvoker)e.Result;
      callback.Invoke();
   }

   // Do nothing but sleep
   static void DoWork(object sender, DoWorkEventArgs e)
   {
      object[] args = (object[])e.Argument;
      Thread.Sleep((int)args[0]);
      e.Result = args[1]; // return callback
   }
}


After that we can easily use that class in our main UI thread as follows where we can easily track the business logic.
C#
...
label1.Text = "Powering on device";
device.PowerOn();

//Check device status 10 seconds later

DelayedAction.Do(10000, (MethodInvoker)delegate()
{
   // UI can be direcly manipulated here
   // This code executes in the UI thread.
   if( device.IsPowered() == false )
   {
      label1.Text = "Device operation failed";
   }
   else
   {
      label1.Text = "Device OK.";
   }
 });
 ...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)