WPF Common TaskDialog for Vista and XP

WPF custom TaskDialog that renders the same on Vista and XP. This custom dialog simplifies programming by providing a simple interface for developers that is not Operating System dependent. This solution does not use the Windows API for rendering.

Introduction

This article covers an important topic, dialog boxes. With the release of Vista came the cool TaskDialog that all Vista users are getting used to. It provides a richer dialog than the standard message box dialog available on Windows XP.

However, this great new feature causes a minor bump in the carpet for WPF developers. Which dialog should WPF developers use? Should WPF developers customize their dialogs for each Operating System? What about application documentation? Should documentation have to cover two flavors of every dialog box? The TaskDialog clearly provides for much more information than the message box, so what to do?

This is the very question that tapped on my shoulder about three months ago. So I developed a custom dialog class that works on both Vista and XP. It looks just like Vista's TaskDialog, yet without all the messy API business. (Microsoft, please add TaskDialog to the 3.6 Framework so we WPF developers do not need to fool with the Windows API and so that it can be an Operating System independent feature.) If you're interested in looking at the Windows API TaskDialog code, you can have a look at the VistaBridge application in the Windows Vista SDK.

We will look at some dialog usage examples and then have a look at some of the code.

Features

Same simple interface for WPF developers programming against Vista or XP

Common icons and text allow for standard documentation for Vista and XP

The above image was captured after the delay timer had completed and the user had clicked "See Details" which exposed the AdditionalDetailsText information.

Comparing the two images with the CommonDialog.CustomDialog properties makes it very easy to see where each property is displayed.

You can also see how the dialog will look on a Windows XP system.

Allow me to touch on the ButtonsDisabledDelay property. Many times, our beloved users are quick on the keyboard or mouse and just click through important dialog boxes. They tend to tell customer support, "I never saw that box!" For those users (I can smell a new user profile setting), or for very important dialog boxes, the ButtonsDisabledDelay property was added. Assign how many seconds you want the buttons to be disabled before the user can respond to the dialog box. Since this dialog can't be closed with the little red X or by pressing ALT-F4, your user will have plenty of time to actually read and digest the information you are trying to communicate. Just don't get too crazy with the delay feature.

Vista and XP Differences

The only difference in the way this custom dialog renders is that on Vista, the dialog takes advantage of Aero Glass and, if available, uses it on the Window chrome. On XP, the custom dialog uses the system XP Window chrome.

CommonDialog Project

The above CustomDialog class provides the public interface for the CommonDialog project. Consumers instantiate and set properties on this class and call the Show method to display the CustomDialogWindow. The CustomDialog class constructs the CustomDialogWindow and returns the result after logging the user's dialog actions (see optional logging feature below).

Logging Feature

The CommonDialog.CustomDialog class provides a Private Sub LogDialog procedure that gets called when the user closes the dialog. By default, this procedure has no code, since the actual implementation would be very specific to each user's application and requirements. However, developers can very easily use this stub to provide rich dialog logging to their applications.

In addition to the properties used to construct the dialog and the user's response, the following properties can also be logged:

The above code snippet shows how the CallingMethodName, CallingModuleName, and CallingReflectedTypeName properties are populated. This information can be helpful to developers trying to troubleshoot an issue and the user was not sure what they did.

Aero Glass

The VistaAeroAPI class allows developers to use Aero Glass in their WPF windows. There are so many Internet examples of extending Aero Glass in C#, so I've included this class here which is written in VB.NET.

Using Aero Glass

Aero Glass is a feature of Windows Vista. So XP users do not have this feature. Additionally, Vista users can turn Aero Glass off. So, when using this feature in your applications, you must be able to handle XP and Aero-off situations.

The first logical step when working with the Aero Glass feature is to determine the Operating System version. I have elected to perform this check in the constructor using this code: System.Environment.OSVersion.Version.Major < 6.

When using the Aero Glass feature, you need to Override the WindowOnSourceInitialized method and place your Aero Glass code here.

This is also the location to handle non-Aero or Aero-off scenarios. In the case of this application, I have coded the Window object, setting its properties, assuming that Aero Glass will be available and enabled. In the above code, if the Operating System is XP, then a small amount of adjustments are necessary to make the dialog Window look the same or as close as possible to the Vista Aero dialog. Likewise, if the Operating System is Vista and the Aero Glass feature is turned off, a few small adjustments are made to the Window object to make it look good even without Aero.

This is an important and necessary step when implementing Aero Glass in your WPF applications.

Additional Resources

I have started a WPF Sample Series on my blog. I will be posting 3-6 WPF Sample Applications a month. I won't be posting every sample here on CodeProject, but you can still read them and download the code from my blog.

Comments and Discussions

Thanks for this article - it is very helpful. By moving from a Forms messagebox to the wpf based TaskDialog (similar to this sample) we have been able to solve several problems, and improve the look of our app.

I have found somewhat inexplicably that I sometimes get clipping of the button and See Details expander. This tends to happen when we have newlines in our message, which we had done regularly in the messagebox. I can replicate this is the sample as follows:

OK, I just read the comment below "Very nice work" and I can see the recommendation to add Margin="0,0,10,0" to the TextBlock - a quick test indicates that does indeed solve this issue. I guess I wonder if it will arise again for a particular combination of heights and word wrap.... I will continue to test in our app.
Tim