Click here to Skip to main content
Licence CPOL
First Posted 19 Dec 2010
Views 22,590
Downloads 1,462
Bookmarked 62 times

WPF TaskDialog Wrapper and Emulator

By | 22 Dec 2011 | Article
A TaskDialog wrapper class with fallback emulator (for XP and earlier)

The Short Version

Really quickly, here's what you need to know:

  • Visual Studio 2010 solution in .NET 4.0 for WPF applications
  • Uses native TaskDialogIndirect calls when available (Vista/7)
  • Uses an emulated WPF version when not (XP)
  • Provides seamless fallback, lots of customizability, and detailed return results
  • Completely free to use or modify
  • Lots of improvements in v1.5 — see below!

Introduction

I've been a big fan (and user) of Hedley Muscroft's WinForms emulator and wrapper for TaskDialogs. In that same spirit, I've taken part of his hard work (and, by succession, KevinGre's) and done something very similar, but this time for WPF (and .NET 4.0).

Background

There are tons of other WPF/WinForms TaskDialog implementations out there, either those that wrap the Win32 APIs, or just providing a custom WPF dialog to use. A quick web search will find you plenty. What they don't give you is a unified way to use the native dialog that still works on older versions of Windows. I go into more detail on the rationale and history of all this in a blog post here.

Hedley's work is great and I've used it plenty of times, but I wanted something very similar that worked for WPF apps. I also thought I might take the time to try to improve on it, mostly thanks to the power of WPF and .NET 4.0.

Using the Code

For the most part, you'll only care about the TaskDialog class' static methods for invoking a dialog. I wanted it to sort of mimic the ease of use that the traditional MessageBox class has always given us. There are two other major classes that you'll use with the static methods:

  • TaskDialogOptions
  • TaskDialogResult

For cases where you need complete control over the customization of the task dialog, you'll have to create an options object and pass it in to the Show method. This means you can't exactly do a one-line method call anymore, but it does give you the most control in cases where that is important.

In simple cases, you'll get back an enum value, much like MessageBox returns (in fact, it is directly cast-able to DialogResult) that will let you know which button was clicked by the user. In the more complicated cases, especially when using an options object, you'll get back a full result object that includes everything you need to know about what the user did to your task dialog. You'll get back the index of any radio button selected, command link clicked, or common/custom button clicked.

Here's some code to show a dialog:

TaskDialogOptions config = new TaskDialogOptions();

config.Owner = this;
config.Title = "Task Dialog Title";
config.MainInstruction = "The main instruction text for the TaskDialog goes here";
config.Content = "The content text for the task dialog is shown " + 
                 "here and the text will automatically wrap as needed.";
config.ExpandedInfo = "Any expanded content text for the " + 
                      "task dialog is shown here and the text " + 
                      "will automatically wrap as needed.";
config.VerificationText = "Don't show me this message again";
config.CustomButtons = new string[] { "&Save", "Do&n't save", "&Cancel" };
config.MainIcon = VistaTaskDialogIcon.Shield;
config.FooterText = "Optional footer text with an icon can be included.";
config.FooterIcon = VistaTaskDialogIcon.Warning;

TaskDialogResult res = TaskDialog.Show(config);

And here's the corresponding dialog emulated on Windows 7 and Windows XP:

Emulated Task Dialog in Windows 7

Emulated Task Dialog in Windows XP

Accelerator keys can be specified (as per the Win32 API for TaskDialogs) by preceding the character with an ampersand (&), as seen in the above code. As you may already know, in WPF, accelerators are denoted by an underscore, but the emulated dialog accounts for this difference automatically.

Clickable hyperlinks can be specified by using the HTML equivalent anchor tag around some part of the text. Only the Content, ExpandedInfo, and FooterText properties support hyperlinks. You can use a callback handler to catch the clicks. Whatever value was specified as the href attribute can be used in the callback. An example can be found in the test project.

When using an options object, anything you leave blank or unspecified will simply not be shown, making it very flexible. You can also modify the static TaskDialogOptions.Default instance to set defaults and use it to create new options objects in the future. As an example, it might be useful to have the title caption always say your application's name by default unless specified. Since the options object is a struct value-type, you'll write TaskDialogOptions config = TaskDialogOptions.Default; instead of using the new operator as shown above.

Included in the source is a test application, much like Hedley's, that will let you try out several different kinds and see both the native (provided you are on Vista/7, of course) and emulated versions as well as what kind of information they return. I encourage you to look through the test project's code to see how it is showing task dialogs to get an idea of how to do the various kinds of dialogs.

Test Application

More Examples

The following examples each show the code to invoke plus the corresponding dialog in native, emulated on Windows 7, and emulated on Windows XP, respectively. You can easily see that the emulated dialog is very close to the native, even on XP, and the icons are specific to the version of the OS running, too.

Showing a full error message:

TaskDialog.ShowMessage(this,
    "Outlook",
    "ActiveSync can't log on to Outlook",
    "Make sure that Outlook is installed and functioning correctly.",
    "You may need to restart your computer. You could have a conflict "

    + "due to two folders on this computer are name C:\\Program Files\\Microsoft "
    + "and C:\\Program Files\\Microsoft Office. If so, rename the "
    + "C:\\Program Files\\Microsoft folder so that it does not contain the word "
    + "\"Microsoft.\" If this folder contains subfolders, you may need "

    + "to reinstall programs in the renamed folder.\n\nFor more information "
    + "on renaming folders and installing programs, see Help for your "
    + "operating system.",
    null,
    null,
    TaskDialogCommonButtons.Close,
    VistaTaskDialogIcon.Error,
    VistaTaskDialogIcon.None);

Message box

Message box emulated on Windows 7

Message box emulated on Windows XP

Showing radio button options:

TaskDialogOptions config = new TaskDialogOptions();

config.Owner = this;
config.Title = "RadioBox Title";
config.MainInstruction = "The main instruction text for the TaskDialog goes here.";
config.Content = "The content text for the task dialog is shown here "
               + "and the text will automatically wrap as needed.";
config.ExpandedInfo = "Any expanded content text for the task dialog "

                    + "is shown here and the text will automatically wrap as needed.";
config.RadioButtons = new string[] {
    "Radio Option 1", "Radio Option 2", 
    "Radio Option 3", "Radio Option 4", "Radio Option 5" };
config.MainIcon = VistaTaskDialogIcon.Information;

TaskDialogResult res = TaskDialog.Show(config);

Radio button box

Radio button box emulated on Windows 7

Radio button box emulated on Windows XP

Showing command links:

TaskDialogOptions config = new TaskDialogOptions();

config.Owner = this;
config.Title = "RadioBox Title";
config.MainInstruction = "The main instruction text for the TaskDialog goes here.";
config.Content = "The content text for the task dialog is shown here "
               + "and the text will automatically wrap as needed.";
config.ExpandedInfo = "Any expanded content text for the task dialog "

                    + "is shown here and the text will automatically wrap as needed.";
config.CommandButtons = new string[] {
    "Command &Link 1", "Command Link 2\nLine 2\nLine 3", "Command Link 3" };
config.MainIcon = VistaTaskDialogIcon.Information;

TaskDialogResult res = TaskDialog.Show(config);

Command link box

Command link box emulated on Windows 7

Command link box emulated on Windows XP

Using custom icons

Add the icon to your project with a Build Action of Resource. I just added mine via the default Resources.resx file as an Image resource.

TaskDialogOptions config = new TaskDialogOptions();

config.Owner = this;
config.Title = "Windows Genuine Verification";
config.MainInstruction = "This copy of Windows is not genuine.";
config.Content = "You may be a victim of software counterfeiting.";
config.CommonButtons = TaskDialogCommonButtons.Close;
config.CustomMainIcon = System.Drawing.Icon.FromHandle
			(Properties.Resources.genuine_32.GetHicon());

TaskDialogResult res = TaskDialog.Show(config);

Don't forget to dispose of it when you're done! (example: config.CustomMainIcon.Dispose();)

Task dialog box with custom icon

Showing progress bars:

TaskDialogOptions config = new TaskDialogOptions();

config.Owner = this;
config.Title = "Downloading File...";
config.MainInstruction = 
"Your file 'en_visual_studio_2010_ultimate_x86_dvd_509116.iso' is currently downloading";
config.Content = "Time elapsed: 00:00 | Download rate: 0 KB/s";
config.CustomButtons = new string[] { "&Reset Timer", "&Cancel" };
config.AllowDialogCancellation = true;
config.ShowProgressBar = true;
config.EnableCallbackTimer = true;
config.Callback = taskDialog_Callback2;

TaskDialogResult res = TaskDialog.Show(config);

In the callback handler, you'll process timer events to update the progress bar's value or you can opt for a marquee (indeterminate) style. There's a pretty nice example implementation in the test project I suggest you take a look at. Callbacks are one of the more tricky things to handle but they can be very powerful.

Progress bar box

Progress bar box emulated on Windows 7

Progress bar box emulated on Windows XP

Known Limitations/Bugs

Currently, though these features work in the native TaskDialog, they are not (yet) exposed by this wrapper:

  • Window position placement
  • Right-to-left layouts
  • Auto and custom window sizing
  • On Windows XP, the emulated dialog still shows the icon sometimes (native TaskDialogs and emulated dialogs on Vista/7 never show an icon)

Also, the emulated form could probably stand to have smarter auto-sizing logic. The native dialog seems to have this, but the exact rules for it are not exactly documented or obvious. I also didn't bother to try to implement the fancy fading and resizing animations that the native dialog uses when toggling the show/hide details button. It's not obvious from the static screenshots, but the emulated command link is very close to the native and has all the animations, too.

Please note any bugs or corrections in the comments.

History

  • 12/17/2010 - v1.0
    • Initial public release
  • 2/7/2011 - v1.0.1
    • Now uses DesignData feature of Visual Studio
    • Fixed a bug with default radio button selection (thanks pt1401)
    • Alt-F4 is now properly ignored by the emulated Task Dialog, when appropriate
  • 11/1/2011 - v1.1
    • Added an AllowDialogCancellation property to TaskDialogConfig
  • 11/2/2011 - v1.1.1
    • Fixed DefaultButtonIndex to work with the native Task Dialog (thanks Filip D'haene)
  • 12/21/2011 - v1.5
    • Added support for callbacks, progress bars, hyperlinks, and custom main/footer icons
    • Added support for several more customization options: expand footer (default is content), expanded by default, verification checkbox default state
    • While the core task dialog code is now mostly stable, these new features should be considered experimental for now
    • Fixed RadioButtonResult to not override the SimpleResult, so you can still see what button the user clicked (such as Cancel) as well as what radio item was selected (thanks in part to awrdsemb)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sean A. Hanley

Software Developer

United States United States

Member

Follow on Twitter Follow on Twitter
I'm a C# .NET developer for both Windows and Web applications since 2007, with a background in C/C++. Due to my job responsibilities currently, I've worn many hats. T-SQL in SQL Server, WinForms, WPF, WCF, ASP.NET, JavaScript, CSS, and more.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionStyling Pinmemberdreamgarden20:10 8 May '12  
AnswerRe: Styling PinmemberSean A. Hanley20:15 8 May '12  
Questiondont show me again Pinmemberhanonymouss15:48 28 Dec '11  
AnswerRe: dont show me again PinmemberSean A. Hanley4:52 29 Dec '11  
GeneralRe: dont show me again Pinmemberhanonymouss3:42 30 Dec '11  
GeneralRe: dont show me again PinmemberSean A. Hanley7:53 30 Dec '11  
GeneralRe: dont show me again Pinmemberhanonymouss13:56 30 Dec '11  
AnswerRe: dont show me again PinmemberSean A. Hanley12:17 5 Apr '12  
SuggestionShutdown problem Pinmembermarkusml3:26 2 Dec '11  
GeneralRe: Shutdown problem PinmemberSean A. Hanley7:24 2 Dec '11  
Questionthemes in WPF Pinmembertomtom19802:40 17 Nov '11  
AnswerRe: themes in WPF PinmemberSean A. Hanley3:43 19 Nov '11  
SuggestionCannot cancel a dialog with radio buttons Pinmemberawrdsemb6:54 7 Nov '11  
GeneralRe: Cannot cancel a dialog with radio buttons PinmemberSean A. Hanley9:00 7 Nov '11  
Bugcannot set the focus right with CustomButtons PinmemberFilip D'haene6:11 2 Nov '11  
GeneralRe: cannot set the focus right with CustomButtons PinmemberSean A. Hanley10:16 2 Nov '11  
GeneralRe: cannot set the focus right with CustomButtons PinmemberFilip D'haene22:55 3 Nov '11  
SuggestionEsc key not working [modified] Pinmembercesnek5:02 1 Nov '11  
GeneralRe: Esc key not working PinmemberSean A. Hanley5:17 1 Nov '11  
GeneralRe: Esc key not working Pinmembercesnek5:21 1 Nov '11  
GeneralRe: Esc key not working PinmemberSean A. Hanley6:39 1 Nov '11  
GeneralRe: Esc key not working Pinmembercesnek7:33 1 Nov '11  
GeneralRe: Esc key not working PinmemberSean A. Hanley8:08 1 Nov '11  
GeneralRe: Esc key not working Pinmembercesnek12:01 1 Nov '11  
GeneralRe: Esc key not working PinmemberSean A. Hanley14:18 1 Nov '11  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120517.1 | Last Updated 22 Dec 2011
Article Copyright 2010 by Sean A. Hanley
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid