Loading Bitmaps: DoEvents and the closure pattern

WPF DoEvents

DoEvents and the closure pattern

Sometimes loading a bitmap causes an asynchronous download and you have to wait for it to complete before using it - but how best to wait? The standard solution is to use an event but this breaks what would otherwise be a sequential flow. Can reinventing DoEvents save the day or is the closure pattern a better bet?
For more information on  loading bitmaps from local file sources and how to tell if a bitmap is going to be downloaded or not see: BitmapImage and local files
BitmapImage
Although BitmapSource is the base class for most of the bitmap facilities in WPF it is the BitmapImage class that you are likely use most of the time. The BitmapImage class has all of the methods of the BitmapSource class but as the Create method is static and only creates BitmapSource objects you need alternative methods of creating a BitmapImage.
In most cases you will use BitmapImage with a bitmap file either stored on the local disk or stored on a web server. Loading a bitmap from a web server  usually occurs asynchronously and this creates a problem - how do you wait until the bitmap has finished loading? There are no built-in facilities for synchronous blocking bitmap loads. However, we can make up for this lack by either reinventing the "DoEvents" method or, much better, using the closure pattern.
There is an additional problem in that you can't know if the system will use a background download or not because it depends on the file's location. In all cases, however, a file specified as "HTTP" will be downloaded in the background.
Loading Bitmaps
When you create a BitmapImage you can specify a URI to the file and it will be loaded as and when it is needed. For example:
 BitmapImage bmi = new BitmapImage( new Uri(@"http://MyWebSite/images/MyPic.png"));
This sets the BitmapImage source to the specified URI and starts it downloading asynchronously.
Until the download is complete its properties are set to default values. For example, if you try to use the PixelHeight property you will discover that it is set to one.
If you now use the bitmap, for example:
image1.Source = bmi;
nothing appears until the download is complete.
Detecting when loaded
This raises the question of how to detect when a bitmap has finished downloading. The simple answer is that there are a number of events which are triggered during and after the download completes. In particular the DownloadComplete event occurs when the bitmap is ready to use.
To add a handler:
 bmi.DownloadCompleted += new EventHandler(downloadcomplete);
you need to define a method with the correct signature:
void downloadcomplete(object sender,EventArgs e)
{
  textBox1.Text = bmi.PixelHeight.ToString();
}
In this case you can rest assured that you will get the correct PixelHeight.
Synchronous blocking download
There is also an IsDownloading property that is true if the bitmap is downloading and false if it isn't. The prime use of this property is to decided if the bitmap is being downloaded in the background or not.
In this sense you should test the value of this property before assuming that any of the download events will actually occur, but for simplicity this step is left out of the following examples.
However if you think about the IsDownloading property you might be tempted to try to convert the download into a synchronous blocking download using something like:
 while (bmi.IsDownloading) {}
This doesn't work because the thread that you are using is the UI thread and the loop that you have written blocks it from updating the IsDownloading property - or anything else for that matter.
You can try to wriggle to make this work but it is very difficult if not impossible as there is no WPF equivalent of DoEvents.
For example you might try to be kinder and not hog the processor in the while loop by adding:
 while (bmi.IsDownloading) {
  System.Threading.Thread.Sleep(1000); 
 }
but this does no good because all you have succeeding in doing is putting the UI thread to sleep for 1 second and this again stops it updating anything.
DoEvents and the Dispatcher
One solution to the problem is to reinvent the DoEvents function but this isn't straightforward as WPF uses a different message system to Windows Forms. It doesn't use a message queue and its associated low level functions but a Dispatcher object which most controls are descended from. The UI thread is associated with a single Dispatcher object which manages the messages on their way to the controls via a prioritised queue.
The essential point is that the Dispatcher only gets to run when the UI thread has nothing more urgent to do - it doesn't run when you give it a tight loop to execute and putting the UI thread to sleep doesn't help.
The only way to allow the Dispatcher object to process its queue is to somehow tell the UI thread to execute the Dispatcher's processing loop. This doesn't seem possible but you can create and run a new processing loop, called a DispatcherFrame, on the same thread.
The details of how this all works are quite tricky so let's examine how it works in a step-by-step manner.
The simple-minded approach to the problem simply creates a new DispatcherFrame and uses the PushFrame method to start it running:
 DispatcherFrame frame = new DispatcherFrame();
 Dispatcher.PushFrame(frame);
This effectively transfers the attention of the UI thread to the new DispatcherFrame which then processes the Dispatcher's queue - and continues to do this forever.
What this means is that after PushFrame any subsequent instructions are ignored as the UI thread is running the Dispatcher's queue and never returns.
What we need is an action on the Dispatcher's queue that will stop the new DispatcherFrame at an appropriate time. The solution is to simply use the Dispatcher's Invoke method to add an action to its queue with a suitably low priority. When the new low priority action is executed then you can be sure that a lot of higher priority actions that were ahead of it in the queue have been completed.
To stop the DispatcherFrame from processing the queue all we have to do is set its Continue property to false. So we need to arrange to add a delegate something like:
 delegate(object param)
 {
   frame.Continue = false;
   return null;
 }
to the queue with a low priority to bring the UI thread back to process the remaining instructions.
Putting this all together gives:
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(
      DispatcherPriority.Background,
      new DispatcherOperationCallback(
        delegate(object param)
        {
          frame.Continue = false;
          return null;
        }),
      null);
Dispatcher.PushFrame(frame);
Notice that the first parameter of the BeginInvoke specifies the priority and how long the DispatcherFrame gets to run depends on how this is set - it will process all actions with a higher priority before returning. Also notice that the variable "frame" is accessible to the delegate because C# implements a closure which keeps the environment that the delegate was defined in active when it is invoked.
You can easily turn this into a DoEvents method: 
public void DoEvents()
{
 DispatcherFrame frame =
           new DispatcherFrame();
 Dispatcher.CurrentDispatcher.
     BeginInvoke(
      DispatcherPriority.Background,
      new DispatcherOperationCallback(
       delegate(object param)
       {
        frame.Continue = false;
        return null;
       }),
      null);
 Dispatcher.PushFrame(frame);
}
And with a DoEvents method you can now write a blocking wait for download as:
 while (bmi.IsDownloading) {
   DoEvents()
 }
Of course in the real world you would need to add a test to make sure that the loop did actually end at some point after a reasonable time. 
 
DoEvents, threading and closure
You can use the DoEvents approach in any situation where you need to give the UI time to update while you wait or get on with some long task on the UI thread. Of course this whole approach can be criticised on a number of grounds. There is the obvious issue of doing anything by polling in this way in an event-oriented world. Then there is the point that if you want to do things like this then you should use another thread.
However, there is the problem that all WPF controls can only be accessed by the thread that created them. If you create a thread to load a bitmap then interacting with the UI is difficult because the UI and the bitmap have been constructed on different threads and you need to manage the cross thread access using the Dispatcher's Invoke method. This is not easy and, unless you are an expert it is potentially error prone - well it's error prone even if you are an expert. The makes the DoEvents approach seem more attractive if not theoretically elegant.
Is there another way?
The Closure Pattern
Mention of C#'s closures suggests that perhaps there is a way of simply writing the DownloadCompleted event handler as if it was just part of the routine that creates the bitmap. The problem with placing the processing after the bitmap has loaded to an event handler is that in general this doesn't share the same scope as the original method, i.e. it doesn't have access to the same local variable. For example, if you have a method that creates a bitmap:
private void button1_Click(object sender, RoutedEventArgs e)
{
BitmapImage bmi = new BitmapImage(new Uri(@"http://MyWebSite/images/MyPic.png"));
bmi.DownloadCompleted += new EventHandler(downloadcomplete); }
Then the event handler written most naturally as:
void downloadcomplete(object sender,EventArgs e)
{
 textBox1.Text = bmi.PixelHeight.ToString();
}
can't possibly work because bmi is local to button1_Click.
The problem is that there is no continuity of scope or environment between the method that creates the bitmap and the event handler that processes it after it has loaded. What you want to write is something like:
create and load bitmap
get on with other things until bitmap is loaded
do things after bitmap is loaded
You can do this using the DoEvents loop, but you can also do it with a closure. If you define a function within another function then the nested function will be executed in the context of the containing function - no matter when this occurs, even after the containing function has terminated. This seems very strange and many programmers struggle to cope with the crazy logic of a closure which seems to allow a function access to variable that no longer exists.
 
However, if you are simply trying to wait until an asynchronous event has completed before continuing where you left off, a closure is natural. For example, if we recast the previous example as:
private void button1_Click(object sender, RoutedEventArgs e)
{  BitmapImage bmi = new BitmapImage(new Uri(@"http://MyWebSite/images/MyPic.png"));  bmi.DownloadCompleted+=new EventHandler(  delegate(object sender1, EventArgs e1)     {      textBox1.Text = bmi.PixelHeight.ToString();     }); }
then everything works even though the bmi variable is out of scope when the event handler runs - bmi is preserved just so that the event handler can make use of it.
 
You can almost think of the pattern:
instructions that create 
something that has to wait for
an asynchronous event on object O
O.event+=new EventHandler(
              delegate(parameters)

{
  instructions that work with
 all of the variables defined   
  within the function after
  the event has occurred

}
as being equivalent to:
instructions that create 
something that has to wait for
an asynchronous event on object O
wait for event while doing something else
instructions that work with all of the
variables defined within the function
after the event has occurred
The combination of the nested event handler and the closure gives you a neat way of waiting for an event and then continuing within the same execution context - as if the event handler was part of the original method.
This approach to using closures doesn't have any of the disadvantages of DoEvents and it is simple and in the spirit of the language.

Many of the situations where a DoEvents seems to be called for are often put down to lazy programming - you should use additional threads - but event handling solves the problem much more simply without the complication of additional threads and it keeps the UI just as responsive.