Once in a while, you get an extensive screen update to do. I mean that kind of refresh that invalidates many UI components and makes your desktop application look like a loading webpage. During these updates, many components need to be painted one at a time to obtain the final screen. The problem occurs when the update spans multiple paint events thus making techniques like double buffering hard to use. Worst of all, your users keep complaining about this amateur look and, of course, you don’t feel like an amateur. So you dream of a way to hide your work in progress and only show the end result, don’t you?
This is what this component is all about: freezing parts of the user interface until all drawings are done, even for many paint events. And then, just to sweeten things, the new content is smoothly blended with the old one using a nice fade effect. So now, you get it: this is your chance to add a web 2.0 taste to your desktop application.
If that sounds interesting, here is a Visual Studio 2005 C# loading curtain form ready to be integrated into your project. I named it a “curtain” for it is similar to a theatre curtain which hides actors while they are setting up the next scene.
Why not use the double buffering technique?
Maybe, you’ve heard of the Windows Forms
DoubleBuffered property and think that it should work just fine. While it may be handy in some situations, it has some limitations for our problem at hand:
- Not always possible or easy since some components may not be under your control. For example, when you have a COM component that directly draws itself using a device context, the buffering technique is not an option.
- Doesn’t span multiple paint events. So when multiple components need to be painted, you have to make sure that they do all at the same time or otherwise, you will end up with the webpage loading syndrome.
- Not easy to target only parts of the screen.
- No solution out of the box to apply a fade effect (so forget about the web 2.0 spice).
- Rather heavyweight when all you want is to hide something for a quarter of a second!
How it works conceptually
- Just before updating the UI, you put the curtain over the screen area.
- The curtain takes a screen snapshot, and displays this still image to the user.
- Meanwhile, you do the hard update work, and rearrange the screen without causing your user an epileptic crisis.
- When you’re done, you fade the curtain and let the user see your artwork.
How it works in code
- Import the curtain into your project. To do so with Visual Studio 2005, go to ‘Project’, then ‘Add existing item’, and browse for the curtain’s file CurtainForm.cs.
- Create your curtain object and configure it. If you want to update multiple UI parts at the same time, you just create multiple curtains!
MT.CurtainForm myCurtain = new MT.CurtainForm();
- Show your curtain in front of the control to be updated (most common case):
Or manually set the area to be updated:
myCurtain.Bounds = new Rectangle(x, y, width, height);
- Finally, fade your curtain:
Or hide it without the fade effect:
These settings are very fine grained, and are provided only for the more fanatical of you!
Indicates the total time of the fade in milliseconds. Personally, I use a 250ms time since it is not too long to be annoying, and just enough to let the user properly see what has been changed.
This is the animation accuracy or quality. Like the frames per second in video games, and you can use more or less CPU power. You specify the accuracy by setting the duration of each frame in milliseconds. So if you set 50ms per frame, this is equivalent to 20 frames per second.
Indicates whether the user can click through the curtain while it is fading. This has no effect when not fading since the goal of the curtain is to hide what's going on behind. Useful when using a long fade duration since the user can interact with the new content immediately.
Cannot resize the area while displaying the curtain. To avoid resize, I use the following code in the container form:
Before showing the curtain:
MinimumSize = this.Size;
MaximumSize = this.Size;
Once the curtain is hidden:
MinimumSize = new Size(0,0);
MaximumSize = new Size(0,0);
If your window cannot be resized, then this is not an issue for you.
The example project consists of two groups of listboxes that can be updated. One group using the curtain, and another that doesn’t. The example illustrates the problem when multiple UI components need to be refreshed: they cannot be refreshed all at the same time. If you find that the listbox update is not really a problem (since calling
EndUpdate will hide intermediate results after all), imagine that instead of listboxes, we have some cool custom controls.
This “curtain technique” is lightweight and reusable whatever the UI components that need to be hidden are. I created it while working with the MSHTML component (the Microsoft HTML editor). I needed a way to hide all the webpage loading work, which is a little bit annoying when editing with a desktop application. Of course, I’m a professional.