I have made a helper class to the TaskDialog method that is featured in the Windows API Code Pack (available for a couple of months now), which gracefully downgrades the TaskDialog to a standard System.Windows.Forms.MessageBox if the client operating system is not supported, ie. if the client is not using Windows Vista or higher.
As you may note with the current TaskDialog implementation in the API Code Pack, an exception is thrown if you cannot support TaskDialog which I feel makes this class fairly useless by itself in real-world scenarios as you would generally put a wrapper around this anyway unless you are making a program specifically targetting a Vista or higher Operating System.
If you aren’t sure what TaskDialogs are, have a look at the first image on the Windows User Experience Interaction Guidelines, Dialog Boxes section.
SHOW ME THE CODE …
public static class AppHelper
{
public const string APPLICATION_TITLE = "My App Title";
/// <summary>
/// Display "Vista-style" Task Dialog or fallback MessageBox() on pre-Vista machines.
/// </summary>
/// <param name="owner"></param>
/// <param name="dialogTitle"></param>
/// <param name="instruction"></param>
/// <param name="body"></param>
/// <param name="footer"></param>
/// <param name="buttons"></param>
/// <param name="mainIcon"></param>
/// <param name="footerIcon"></param>
/// <returns></returns>
public static TaskDialogResult ShowMessageBox(IWin32Window owner,
string dialogTitle,
string instruction,
string body,
string footer,
TaskDialogStandardButtons buttons,
TaskDialogStandardIcon mainIcon,
TaskDialogStandardIcon? footerIcon)
{
TaskDialogResult result = TaskDialogResult.Ok;
if (CoreHelpers.RunningOnVista) // or greater
{
var dialog = new TaskDialog();
dialog.Cancelable = true;
dialog.Caption = dialogTitle;
if (footerIcon.HasValue)
dialog.FooterIcon = footerIcon.Value;
dialog.FooterText = footer;
dialog.HyperlinksEnabled = true;
dialog.HyperlinkClick += new EventHandler<TaskDialogHyperlinkClickedEventArgs>(dialog_HyperlinkClick);
dialog.Icon = mainIcon;
dialog.InstructionText = instruction;
dialog.StandardButtons = buttons;
dialog.Text = body;
dialog.StartupLocation = TaskDialogStartupLocation.CenterScreen;
if (owner != null)
dialog.OwnerWindowHandle = owner.Handle;
return dialog.Show();
}
// XP or less
MessageBoxButtons stdButtons = MessageBoxButtons.OK;
if ((buttons &
(TaskDialogStandardButtons.Yes | TaskDialogStandardButtons.No)) ==
(TaskDialogStandardButtons.Yes | TaskDialogStandardButtons.No))
stdButtons = MessageBoxButtons.YesNo;
else if ((buttons &
(TaskDialogStandardButtons.Yes | TaskDialogStandardButtons.No | TaskDialogStandardButtons.Cancel)) ==
(TaskDialogStandardButtons.Yes | TaskDialogStandardButtons.No | TaskDialogStandardButtons.Cancel))
stdButtons = MessageBoxButtons.YesNoCancel;
else if ((buttons &
(TaskDialogStandardButtons.Ok | TaskDialogStandardButtons.Cancel)) ==
(TaskDialogStandardButtons.Ok | TaskDialogStandardButtons.Cancel))
stdButtons = MessageBoxButtons.OKCancel;
else if ((buttons &
(TaskDialogStandardButtons.Ok | TaskDialogStandardButtons.Close)) ==
(TaskDialogStandardButtons.Ok | TaskDialogStandardButtons.Close))
stdButtons = MessageBoxButtons.OK;
else if ((buttons &
(TaskDialogStandardButtons.Retry | TaskDialogStandardButtons.Cancel)) ==
(TaskDialogStandardButtons.Retry | TaskDialogStandardButtons.Cancel))
stdButtons = MessageBoxButtons.RetryCancel;
MessageBoxIcon stdIcon = MessageBoxIcon.None;
if (mainIcon == TaskDialogStandardIcon.Information)
stdIcon = MessageBoxIcon.Information;
else if (mainIcon == TaskDialogStandardIcon.Error)
stdIcon = MessageBoxIcon.Error;
else if (mainIcon == TaskDialogStandardIcon.Warning)
stdIcon = MessageBoxIcon.Warning;
else if (mainIcon == TaskDialogStandardIcon.None)
stdIcon = MessageBoxIcon.None;
DialogResult stdResult = MessageBox.Show(owner,
instruction + Environment.NewLine + body,
APPLICATION_TITLE + " - " + dialogTitle,
stdButtons,
stdIcon);
if (stdResult == DialogResult.OK)
result = TaskDialogResult.Ok;
else if (stdResult == DialogResult.Yes)
result = TaskDialogResult.Yes;
else if (stdResult == DialogResult.No)
result = TaskDialogResult.No;
else if (stdResult == DialogResult.Cancel)
result = TaskDialogResult.Cancel;
else if (stdResult == DialogResult.Retry)
result = TaskDialogResult.Retry;
return result;
}
static void dialog_HyperlinkClick(object sender, TaskDialogHyperlinkClickedEventArgs e)
{
try
{
// Launch the application associated with http links
Process.Start(e.LinkText);
}
catch (Exception)
{
ShowMessageBox(null, "Error", "Could not activate link",
"Could not activate hyperlink, if this is a URL, try visiting the website manually.",
null, TaskDialogStandardButtons.Ok, TaskDialogStandardIcon.Error, null);
}
}
}
I am aware not all TaskDialog properties are mapped up, but feel free to enhance this class to suit your needs.
4 Comments
Nice, this can come in handy
Small bug though; This syntax will always return false:
if(buttons == TaskDialogStandardButtons.Yes && buttons == TaskDialogStandardButtons.No)
perhaps replace it with something like this
if (((buttons & TaskDialogStandardButtons.Yes) == TaskDialogStandardButtons.Yes) && ((buttons & TaskDialogStandardButtons.No) == TaskDialogStandardButtons.No))
Thanks, that’s a good way of doing it. That will teach me for assuming my code works instead of thoroughly testing it
I have updated the sample with a slight streamline on your concept!
Do you mean for the IWin32Window to be a ‘System.Windows.Interop.IWin32Window’ or a ‘System.Windows.Forms.IWin32Window’? Because the standard MessageBox methods require the second, yet my WPF app’s window is the first.
(fyi, I’m running on XP)
Hmm, well I did mean
System.Windows.Forms.IWin32Windowas I was targetting Win Forms. But ifInterop.IWin32Windowworks for WPF go ahead.Post a Comment