Loading Bitmaps: DoEvents and the closure pattern
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


Simple WPF data binding

Find out how WPF data binding really works. It's not the binding object that matters - it's the binding expression.



The bitmap transform classes

WPF bitmaps are immutable but that doesn't mean you can't transform them. Find out about rotation, scaling, changing pixel formatting and how to mangage color profiles.



WriteableBitmap

WriteableBitmap gives you a bitmap object that you can modify dynamically - but exactly how to do this isn't always obvious.



Drawing Bitmaps – DrawingImage and DrawingVisual

 

WPF provides multiple ways to convert vector drawings to bitmaps. Find out how DrawingImage and DrawingVisual work and when to use which. On the way we look at how to create 2D vector drawings.



ISupportInitialize and XAML

For a class to be instantiated by XAML it has to have a parameter-less constructor. This means that properties that might be essential to creating the instance can be initialized in any order and this [ ... ]


Other Articles

<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 © 2015 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.