TaskDialog
PSTaskDialog - Windows Forms Emulated TaskDialog (Spot the difference!)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.
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:
class/enum/struct names with "VistaXxxx" (e.g. TaskDialog -> VistaTaskDialog) for the sake of clarity 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.
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.
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)
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).
A few things to note:
string RadioButtons and string CommandButtons parameters are pipe (|) delimited strings containing each item for the radio buttons and command buttons respectively. 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) 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!
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.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.
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
}
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);
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);
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.
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. System.Drawing.SystemIcons (used by the emulated form) doesn't have one. TaskDialog, so the Vista TaskDialog uses the Information icon instead on Vista when eSysIcons.Question is specified. RadioButton layout and CommandButton font to make it more "Vista-like" public enums out of frmTaskDialog (makes more sense) cTaskDialog.UseToolWindowOnXP (see above for details); CommandButtons now accept \n in the string to wrap to new line and display smaller text cTaskDialog.PlaySystemSounds (thanks to logan1337)ClearTypeGridFit text rendering for an even more Vista-like appearance (thanks to Thorsten Dittmar) 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 formCommandButton can now be used as a standalone button (thanks to SDragon42)