|Loading Bitmaps: DoEvents and the closure pattern|
|Wednesday, 16 December 2009|
Page 2 of 2
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
Then the event handler written most naturally as:
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(
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
as being equivalent to:
instructions that create
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.
|Last Updated ( Friday, 19 March 2010 )|