Loading Bitmaps: DoEvents and the closure pattern
Wednesday, 16 December 2009
Article Index
Loading Bitmaps: DoEvents and the closure pattern
Closure

Banner

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.

Banner


FlexGrid - A Lightweight Data Grid

There are more data grids available than the standard one that comes with WPF. In this article we take a look at FlexGrid for WPF and discover how easy it is to use.


<ASIN:0672329816>

<ASIN:1590598733>

<ASIN:0470285818>

<ASIN:159059360X>

<ASIN:0764549146>

<ASIN:0735613702>



Last Updated ( Friday, 19 March 2010 )
 
 

   
RSS feed of all content
I Programmer - full contents
Copyright © 2014 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.