Click here to Skip to main content
11,928,605 members (49,713 online)
Click here to Skip to main content
Add your own
alternative version


119 bookmarked

WPF TaskDialog Wrapper and Emulator

, 18 Oct 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
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!


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).


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:

    "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.",

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

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 an 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 screenshots, but the emulated command link is very close to the native and does have all the animations, too. 

Leave any bugs, corrections, suggestions, or questions in the comments below.  I generally answer them fairly promptly. 


  • 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)
  • 9/20/2012 - v1.6
    • Added support for ClickButton during callbacks (see demo project in source for example usage)
    • Callback timer is now properly stopped when the emulated dialog is closed (thanks to niemyjski)
    • Changed emulated dialog to show OK button instead of Close when no buttons are specified
  • 10/18/2012 - v1.7 
    • Added additional button click methods by type and index for use in callbacks
    • Callback args now include the button index if the notification is related to a click 
    • Radio buttons can now be programmatically clicked as well
    • Added support for button enabling/disabling and setting elevation required in callbacks
    • Additional info about return values in TaskDialogCallback's XML documentation
    • Emulated form now correctly supports common and custom buttons when showing radio buttons, as well as a default OK when no others are specified 
    • Emulated form now correctly notifies callbacks when the dialog is closed via Esc, Alt+F4, etc.
    • Emulated form no longer has Retry/Cancel buttons mistakenly swapped 


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
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.

You may also be interested in...

Comments and Discussions

SuggestionWorks with VS 2015 at Windows 10 Pin
Axel Steiner13-Aug-15 4:53
memberAxel Steiner13-Aug-15 4:53 
SuggestionMy vote of 5 Pin
Jalal Khordadi5-Mar-15 5:22
memberJalal Khordadi5-Mar-15 5:22 
GeneralMy vote of 5 Pin
mespelbrunn16-Jan-15 8:53
membermespelbrunn16-Jan-15 8:53 
SuggestionSupport for File Dialog.. Pin
eros2007mx13-Aug-14 10:16
membereros2007mx13-Aug-14 10:16 
QuestionSetting owner to WINFORM Pin
Greg Cronin13-Dec-13 9:42
memberGreg Cronin13-Dec-13 9:42 
QuestionUsing radio options and custom buttons Pin
Yves Goergen22-Feb-13 13:25
memberYves Goergen22-Feb-13 13:25 
SuggestionUse named parameters for less code :-) Pin
Yves Goergen22-Feb-13 12:36
memberYves Goergen22-Feb-13 12:36 
BugAlways getting emulated dialog; Focus issues Pin
Yves Goergen22-Feb-13 11:55
memberYves Goergen22-Feb-13 11:55 
SuggestionLocalization Pin
ChrDressler25-Sep-12 10:32
memberChrDressler25-Sep-12 10:32 
GeneralRe: Localization Pin
Sean A. Hanley30-Sep-12 11:57
memberSean A. Hanley30-Sep-12 11:57 
QuestionCommand button click not working with enabled callback Pin
architecton21-Sep-12 3:27
memberarchitecton21-Sep-12 3:27 
AnswerRe: Command button click not working with enabled callback Pin
Sean A. Hanley21-Sep-12 8:26
memberSean A. Hanley21-Sep-12 8:26 
QuestionSupport for Scrollable Region At Bottom Pin
joelGordon5-Sep-12 20:26
memberjoelGordon5-Sep-12 20:26 
AnswerRe: Support for Scrollable Region At Bottom Pin
Sean A. Hanley6-Sep-12 13:16
memberSean A. Hanley6-Sep-12 13:16 
GeneralRe: Support for Scrollable Region At Bottom Pin
joelGordon19-Sep-12 13:41
memberjoelGordon19-Sep-12 13:41 
GeneralRe: Support for Scrollable Region At Bottom Pin
Sean A. Hanley20-Sep-12 11:08
memberSean A. Hanley20-Sep-12 11:08 
QuestionUsing the Marquee ProgressBar? Pin
xXsniperXx12-Aug-12 10:00
memberxXsniperXx12-Aug-12 10:00 
AnswerRe: Using the Marquee ProgressBar? Pin
Sean A. Hanley14-Aug-12 11:17
memberSean A. Hanley14-Aug-12 11:17 
It's a bit confusing, I apologize. Mostly this is due to the API being the way that it is. Although I suppose I could have tried to expose it in a more friendly way. I mostly just wanted to get it implemented/supported at all, since it wasn't to begin with.

Before showing, set ShowMarqueeProgressBar to true. You don't need to set ShowProgressBar to true, but it shouldn't hurt anything if you do. Also, you'll want to set a callback and, typically, set EnableCallbackTimer to true so that you get regular timer events and you can control the progress bar based on some other process you're doing. In my test app example it is a file download. I could have shown a marquee while connecting and determining file size, as during that I have no way of showing determinate progress.

Anyway, as a minimal example, you can handle the Timer notification and do dialog.SetProgressBarMarquee(true, 0); and it should work. However, you should only do this ONCE! Otherwise, it'll sit there stuttering on the initial animation, because every 100ms the timer fires and resets the marquee. Instead, have some kind of boolean you can check so that you only call it the first time the timer fires.

case VistaTaskDialogNotification.Timer:
	if (!_hasSetMarquee)
		dialog.SetProgressBarMarquee(true, 0);
		_hasSetMarquee = true;

Realistically, you'd have special logic to check various conditions on each timer fire to know when to set or unset the marquee animation. You can call dialog.SetMarqueeProgressBar(false); followed by calls to the various other progress methods like range/position to have it return to the normal determinate mode.

Hope that helps!
QuestionClosing the dialog from the callback Pin
Mark Horowitz22-Jun-12 7:36
memberMark Horowitz22-Jun-12 7:36 
AnswerRe: Closing the dialog from the callback Pin
Sean A. Hanley9-Jul-12 8:17
memberSean A. Hanley9-Jul-12 8:17 
GeneralRe: Closing the dialog from the callback Pin
Mark Horowitz10-Jul-12 4:16
memberMark Horowitz10-Jul-12 4:16 
GeneralRe: Closing the dialog from the callback Pin
Sean A. Hanley10-Jul-12 4:30
memberSean A. Hanley10-Jul-12 4:30 
GeneralRe: Closing the dialog from the callback Pin
Amir Burbea20-Sep-12 10:51
memberAmir Burbea20-Sep-12 10:51 
QuestionStyling Pin
dreamgarden8-May-12 21:10
memberdreamgarden8-May-12 21:10 
AnswerRe: Styling Pin
Sean A. Hanley8-May-12 21:15
memberSean A. Hanley8-May-12 21:15 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.151126.1 | Last Updated 18 Oct 2012
Article Copyright 2010 by Sean A. Hanley
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid