Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Vista TaskDialog Wrapper and Emulator

4.95/5 (94 votes)
7 Jul 2009CPOL5 min read 3   3.5K  
A Vista TaskDialog wrapper class (for Vista) and Emulator (for pre-Vista Windows)

Image 1

Windows Vista COMCTL32.dll v6 TaskDialog

Image 2

PSTaskDialog - Windows Forms Emulated TaskDialog (Spot the difference!)

Introduction

After wasting innumerable hours hunting around the internet like a rabid squirrel for a way of using the Vista TaskDialog on pre-Vista versions of Windows, I decided to write one myself. "Necessity is the mother of invention." As I frequent The Code Project's website whenever I need help, I figured it was about time that I gave something back to the community. Hence, this article.

Background

Basically, I wanted a class that would wrap the TaskDialog so that on a Vista machine, it would invoke the native TaskDialog in COMCTL32.dll v6 (which ships with Vista), while on pre-Vista machines, it would emulate the TaskDialog with a near identical substitute. Massive credit must go to KevinGre for his superb article "TaskDialog for WinForms," which wraps the COMCTL32 TaskDialog API. The only changes made to his code were as follows:

  1. Prefixed class/enum/struct names with "VistaXxxx" (e.g. TaskDialog -> VistaTaskDialog) for the sake of clarity
  2. Implemented the bug fix for x64 machines mentioned in the comments section at the bottom of his article

This project takes Kevin's work a step further, in that the TaskDialog is no longer restricted to Windows Vista. You can now use the same code to display a TaskDialog without worrying about the Windows version.

Using the Code

The namespace for this project is PSTaskDialog (Pioneer Software is my company) and the only class that we really need to know about is the static public class cTaskDialog (conveniently located in cTaskDialog.cs). The cTaskDialog class contains a number of static public methods to execute a TaskDialog. The principle method is ShowTaskDialogBox. I say "principle" because this is the routine that does all the work and displays either the Vista TaskDialog or the emulated version. All the other methods in cTaskDialog end up calling this method to invoke the TaskDialog.

C#
static public DialogResult ShowTaskDialogBox(IWin32Window ParentWindow,
                                             string Title,
                                             string MainInstruction,
                                             string Content,
                                             string ExpandedInfo,
                                             string Footer,
                                             string VerificationText,
                                             string RadioButtons,
                                             string CommandButtons,
                                             eTaskDialogButtons Buttons,
                                             eSysIcons MainIcon,
                                             eSysIcons FooterIcon)

Example 1: Using the Full ShowTaskDialogBox Method

C#
DialogResult res =
  PSTaskDialog.cTaskDialog.ShowTaskDialogBox(this,
                                             "The main instruction text for
                                             the TaskDialog goes here.",
                                            "The content text for the task
                                             dialog is shown here and the
                                             text will automatically wrap as
                                             needed.",
                                            "Any expanded content text for
                                             the task dialog is shown here
                                             and the text will automatically
                                             wrap as needed.",
                                            "Optional footer text with an
                                             icon can be included",
                                            "Don't show me this message
                                             again",
                                            "Radio Option 1|Radio Option 2|
                                             Radio Option 3",
                                            "Command Button 1
                                             |Command Button 2\nLine 2\nLine 3
                                              |Command Button 3",
                                            PSTaskDialog.eTaskDialogButtons.
                                            OKCancel,
                                            PSTaskDialog.eSysIcons.
                                            Information,
                                            PSTaskDialog.eSysIcons.Warning);

Here's a screenshot of the above (this is on Vista running in Emulation mode).

Screenshot - demo1.png

A few things to note:

  1. The string RadioButtons and string CommandButtons parameters are pipe (|) delimited strings containing each item for the radio buttons and command buttons respectively.
  2. Sending in an empty string ("") to some of the parameters will disable (i.e. hide) certain features of the TaskDialog, namely:
    • ExpandedInfo (the "Show details" section)
    • Footer (the bottom footer with the icon)
    • VerificationText (the "Don't show this again" check box)
    • RadioButtons (the radio buttons)
    • CommandButtons (the command buttons)
  3. In addition to the DialogResult return value, other information that you may need to know after executing the TaskDialog are saved to the following static public variables of cTaskDialog:
    • VerificationChecked (whether the "Don't show this again" CheckBox was checked)
    • RadioButtonResult (0-based index of the selected RadioButton)
    • CommandButtonResult (0-based index of the clicked CommandButton)

    Please note: I realize that some may feel that ref parameters are a better way of retrieving these values as opposed to public static methods of the cTaskDialog class. Please feel free to change the code to your heart's content!

  4. cTaskDialog also has a few other static public variables to consider:
    • EmulatedFormWidth (default 450). This is the width of the emulated form. Vista seems to do some clever dynamic resizing of the TaskDialog depending on its content. From my testing, 450 pixels seems to be a reasonable width (very similar to Vista in most cases) and it looks fine for most TaskDialog scenarios. Change this value before executing the TaskDialog if you wish.
    • ForceEmulationMode is a bool that forces the emulated Windows Forms version of the TaskDialog to be used on Vista machines (this is really just there for test purposes as there's no real reason to use the emulation mode when running Vista).
    • UseToolWindowOnXP (new in 1.02) is a bool that makes the TaskDialog use a ToolWindow on pre-Vista systems. I think it matches the look of Vista a bit better than the thicker dialog caption bar.
    • PlaySystemSounds (new in 1.03) is a bool that determines whether the TaskDialog plays the default system sound (associated with the MainIcon type) when it is displayed. This defaults to true, so make it false to suppress sounds.

Example 2: Showing a MessageBox

C#
PSTaskDialog.cTaskDialog.MessageBox(this,
                                   "MessageBox Title",
                                   "The main instruction text for the
                                    message box is shown here.",
                                   "The content text for the message box
                                    is shown here and the text will
                                    automatically wrap as needed.",
                                   "Any expanded content text for the
                                    message box is shown here and the text
                                    will automatically wrap as needed.",
                                   "Optional footer text with an icon can be
                                    included",
                                   PSTaskDialog.eTaskDialogButtons.YesNo,
                                   PSTaskDialog.eSysIcons.Information,
                                   PSTaskDialog.eSysIcons.Error);

Shown below is a screenshot of the above on Windows XP. Please compare this image against the top two in this article. The code is exactly the same to produce any of these dialogs.

Screenshot - demo2.png

Example 3: Showing an Even More Simple MessageBox

C#
PSTaskDialog.cTaskDialog.MessageBox(this,
                                   "MessageBox Title",
                                   "The main instruction text for the
                                    message box is shown here.",
                                   "The content text for the message box
                                    is shown here and the text will
                                    automatically wrap as needed.",
                                    PSTaskDialog.eTaskDialogButtons.OK,
                                    PSTaskDialog.eSysIcons.Warning);

if (PSTaskDialog.cTaskDialog.VerificationChecked)
{
  // persist the user's choice here

  // e.g. write a registry entry to remember not to show this next time

}

Screenshot - demo3.png

Example 4: Showing a Radio Listbox

C#
PSTaskDialog.cTaskDialog.ShowRadioBox(this,
                                       "RadioBox Title",
                                       "The main instruction text for the
                                       radiobox is shown here.",
                                      "The content text for the radiobox is
                                       shown here and the text will
                                       automatically wrap as needed.",
                                      "Any expanded content text for the
                                       radiobox is shown here and the text
                                       will automatically wrap as needed.",
                                      "Optional footer text with an icon
                                       can be included",
                                      "Don't show this message again",
                                      "Radio Option 1|Radio Option 2|
                                       Radio Option 3|Radio Option 4|
                                       Radio Option 5",
                                      PSTaskDialog.eSysIcons.Information,
                                      PSTaskDialog.eSysIcons.Warning);

Screenshot - demo4.png

Example 5: Showing a Command Button

C#
PSTaskDialog.cTaskDialog.ShowCommandBox(this,
                                        "CommandBox Title",
                                       "The main instruction text for the
                                        commandbox is shown here.",
                                       "The content text for the commandbox
                                        is shown here and the text will
                                        automatically wrap as needed.",
                                       "Any expanded content text for the
                                        commandbox is shown here and the text
                                        will automatically wrap as needed.",
                                       "Optional footer text with an icon
                                        can be included",
                                       "Don't show this message again",
                                       "Command Button 1|Command Button 2|
                                        Command Button 3|Command Button 4",
                                       true,
                                       PSTaskDialog.eSysIcons.Information,
                                       PSTaskDialog.eSysIcons.Warning);

Screenshot - demo5.png

Please take a look at the source code in Form1.cs in the TaskDialogTest folder to see exactly how cTaskDialog can be used in your code.

Known Limitations

  • I have not implemented the ProgressBar functionality in the emulated TaskDialog, mainly because I have no need of it myself. It shouldn't be too hard to adapt the code if you wish to add this feature.
  • I have omitted the Shield icon that is available under Vista because System.Drawing.SystemIcons (used by the emulated form) doesn't have one.
  • Oddly, there is no Question icon available in the Vista TaskDialog, so the Vista TaskDialog uses the Information icon instead on Vista when eSysIcons.Question is specified.

History

  • 12/11/2007 v1.0
    • Initial release
  • 12/11/2007 v1.01
    • Visual adjustments to RadioButton layout and CommandButton font to make it more "Vista-like"
    • Moved public enums out of frmTaskDialog (makes more sense)
  • 15/11/2007 v1.02
    • Added new cTaskDialog.UseToolWindowOnXP (see above for details); CommandButtons now accept \n in the string to wrap to new line and display smaller text
    • A few more visual tweaks to make it look more "Vista-y" (if that's even a word?!)
  • 25/11/2007 v1.03
    • Added new cTaskDialog.PlaySystemSounds (thanks to logan1337)
    • "Main Instruction" text and Command Button text is now painted with ClearTypeGridFit text rendering for an even more Vista-like appearance (thanks to Thorsten Dittmar)
  • 06/07/2009 v1.04 
    • The public routines can now all take an IWin32Window Owner as the first parameter. This gives more control over the parenting of the TaskDialog both in Vista (or Windows 7) and XP (thanks to grahamoneale). I've added plenty of overloaded routines so that if the Owner is omitted, null is presumed, however it is good practice to specify an Owner form
    • Implemented image resizing improvement (thanks to TheDesertFox)
    • Improved Dispose code (thanks to veki-peki)
    • CommandButton can now be used as a standalone button (thanks to SDragon42)
    • Accelerator keys are now drawn correctly (thanks to Member243669)

License

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