Performing long-running, timed operations on the UI thread

Recently I had to play timed sounds (morse code) in a WP7 applications. Sounds are required to be played on the UI thread, but as I had to time them, my UI thread got frozen. The reason was, that I used Thread.Sleep() to time the sound, which of course blocked the UI thread.

Today I figured out a way to do this long-running operation (many seconds..) without blocking the UI thread. You may know the Visual Studio Async CTP – it’s required to do the trick.

Let’s suppose we already have a method InvokeEvent() that plays the sound, changes a color or something like that.

Currently we execute this method in a pattern like this, causing the UI thread to be blocked:

void StartOperation()//invoke the event in a pattern
{
  for (int i=0; i<20; i++)//20 times
  {
    InvokeEvent();//play the sound, blink with the display or something like that
    Thread.Sleep(500);//this will block the current (UI) thread!
    InvokeEvent();
    Thread.Sleep(150);
  }
}

StartOperation() would be called by a Button_Click-Event handler, or similar.

To do this without blocking the UI thread, we need to avoid calling Thread.Sleep() on it.

So instead we create a Task that does this for us on a different thread. As Tasks can be awaited without blocking the UI thread, we can use it to pause execution of code.

Task MillisecondDelay(int ms)
{
  Task t = new Task(new Action(delegate{
  {
    Thread.Sleep(ms);//we're on the Task's thread, so we can block it!
  }));
  t.Start();
  return t;
}

The new StartOperation() method looks like this:

async void StartOperationAsync()//invoke the event in a pattern
{
  for (int i=0; i<20; i++)//20 times
  {
    InvokeEvent();//play the sound, blink with the display or something like that
    await MillisecondDelay(500);
    InvokeEvent();
    await MillisecondDelay(150);
  }
}

It can be called from any other method, marked with the async keyword. (In this case async void Button_Click)

NOTE: Calling an asynchronous method (like StartOperationAsync()) without awaiting it can be very helpful in certain scenarios (like saving data to the disk, without requiring it to finish before something else is executed).

 

have fun!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>