다음을 통해 공유


.NET Core 5 TaskDialog (C#)

Introduction

When an application requires a message to be display or to ask a user questions the common method is to use a MessageBox.

A standard message box with its many overloads for Show method is fine for simply displaying and asking for input (without a input/textbox) while the TaskDialog provides more flexibilities. With these flexibilities comes more code which can be placed into a separate class in a project or better, place code into a separate class project. To use the class project, add a reference to a project or create a NuGet local package and install the package in any project.

Below find common examples for using a TaskDialog in a Windows Form and WPF projects. And note that there are many more methods to explore in the class project WindowsFormsLibrary.

What does TaskDialog offer over MessageBox

TaskDialog provides many features which range from creating do not show again dialogs, radio and link buttons to events to allow developers to interact with TaskDialog while being displayed. Couple this with the ability to show a progressbar and auto-closing dialog.

With the standard MessageBox it is difficult to control position while with TaskDialog simply pass the owner (caller to the dialog) and set a property to center on a form, window or control and of course centering on the display screen.

Other salient feature is the Icon property can be predefined or set by using an Icon of the developers choice, button choices, positioning and text/labeling.

There are 25 plus examples to learn TaskDialog from, take time to traverse the code rather than simply running the code samples to get a grasp of what is possible.

Front end projects

There are two frontend projects, one Windows Forms and one WPF. The Windows Forms project has more code samples but the WPF project is capable of the same code as found in the Windows Forms project. Why? Generally speaking there are more developers using Windows Forms than WPF.

A third project, AutoCloseNotTaskDialog is a clean way to have a auto closing MessageBox prior to .NET Core 5.

Examples

Auto-closing dialog method

/// <summary>
/// Auto close dialog by specified seconds, if timed out
/// invoke continue button.
/// </summary>
/// <param name="owner">control or form</param>
/// <param name="Icon">icon to present</param>
/// <param name="seconds">seconds to timeout</param>
/// <param name="okText">text for continue button</param>
/// <param name="cancelText">text for cancel button</param>
public static  void AutoCloseDialog(IntPtr owner, Icon Icon,  int  seconds, string  text, string  okText = "OK", string  cancelText = "Cancel")
{
 
    var remaining = seconds * 10;
 
    TaskDialogButton continueButton = new(okText);
    TaskDialogButton cancelButton = new(cancelText);
 
    TaskDialogPage page = new()
    {
        Heading = "To cancel select the cancel button",
        Text = text,
        Icon = new  TaskDialogIcon(Icon),
        Buttons = new  TaskDialogButtonCollection() { continueButton, cancelButton },
        Caption = "Data operations"
    };
 
    using Timer timer = new()
    {
        Enabled = true,
        Interval = 100
    };
 
    timer.Tick += (_, _) =>
    {
        remaining -= 1;
 
        if (remaining != 0) return;
        timer.Enabled = false;
        if (continueButton.BoundPage is not null)
        {
            continueButton.PerformClick();
        }
    };
 
    TaskDialogButton result = TaskDialog.ShowDialog(owner, page);
 
    ContinueOperation?.Invoke(result == continueButton);
 
}

WPF Usage

In this case, a TextBox is setup to accept only numbers and there is a user defined Icon

private void  AutoCloseButton_Click(object sender, RoutedEventArgs e)
{
    int seconds = Convert.ToInt32(SecondsTextBox.Text);
    Dialogs.AutoCloseDialog(_intPtr, _sqlServerIcon, seconds, $"Backing up in {seconds} seconds!!!");
}

Do not show again

Display a dialog which provides an option to not show again or could be used for instance similar to when creating a rule in Microsoft Outlook which has a check box to run the new rule immediately.

Outside of creating a method for do not show again is a place to store the user’s choice. In the code sample provided, their choice is stored in a simple Json file.

/// <summary>
/// A dialog with option to not display again
/// </summary>
/// <param name="options"><seealso cref="ShowAgainOptions"/></param>
/// <returns><seealso cref="NoShowResult"/></returns>
public static  (NoShowResult DialogResult, bool showAgain) DoNotShowAgain(ShowAgainOptions options)
{
 
    TaskDialogPage page = new  ()
    {
        Heading = options.Heading,
        Text = options.Text,
        Caption = options.Caption,
        Icon = new  TaskDialogIcon(options.Icon),
        AllowCancel = true,
        Verification = new  TaskDialogVerificationCheckBox()
        {
            Text = options.VerificationText
        },
        Buttons = new  TaskDialogButtonCollection()
        {
            TaskDialogButton.Yes, TaskDialogButton.No
        },
        DefaultButton = TaskDialogButton.No
    };
 
    if (TaskDialog.ShowDialog(options.IntPtr,page) == TaskDialogButton.Yes)
    {
 
        bool showAgain = false;
 
        if (page.Verification.Checked)
        {
            SettingOperations.SetShowAgain(false);
            showAgain = false;
        }
        else
        {
            SettingOperations.SetShowAgain(true);
            showAgain = true;
        }
 
        return (NoShowResult.StopOperation, showAgain);
 
    }
    else
    {
 
        return (NoShowResult.No, true);
 
    }
 
}

WPF/Windows Forms usage

private void  DoNotShowAgainButton_Click(object sender, RoutedEventArgs e)
{
    var settings = SettingOperations.GetSetting;
 
    if (!settings.ShowAgain) return;
    ShowAgainOptions options = new  ShowAgainOptions
    {
        Heading = settings.Heading,
        Text = settings.Text,
        Caption = settings.Caption,
        Icon = _DatabaseIcon,
        VerificationText = settings.VerificationText,
        IntPtr = _intPtr
    };
 
    (NoShowResult DialogResult, bool  ShowAgain) result = Dialogs.DoNotShowAgain(options);
    ShowAgainCheckBox.IsChecked = result.ShowAgain;
 
}

Class for passing parameters

public class  ShowAgainOptions
{
    public string  Heading { get; set; }
    public string  Text { get; set; }
    public string  Caption { get; set; }
    public string  VerificationText { get; set; }
    public Control Owner { get; set; }
    public IntPtr IntPtr { get; set; }
    public Icon Icon { get; set; }
}

Asking questions

A common practice is to ask a user of an application for permission to continue with a specific operation. This is easy with MessageBox while there are times that the standard buttons do not properly express to the user which option to select, with TaskDialog this is easy as shown in simple easy to understand text in example 2. Both are TaskDialog.

Source code for sending the user's choice to a label.

ComplexLabel.Content = Dialogs.Question(_intPtr, 
    "Question", "Do you like coffee?", 
    "Sure do", 
    "Tea for me") ? 
    "Coffee it is" : 
    "Tea it is";

In the provided source code there are several overloads

Take note of the following which accepts actions where all work is done within the method, not the caller.

/// <summary>
/// Windows Forms dialog to ask a question
/// </summary>
/// <param name="owner">control or form</param>
/// <param name="heading">text for dialog heading</param>
/// <param name="yesAction"></param>
/// <returns>true for yes button, false for no button</returns>
/// <remarks>
/// Dialogs.Question(this, "Ask something", YesMethod, NoMethod);
///
/// Last two parameters are the actions to perform
/// </remarks>
public static  void Question(Control owner, string heading, Action yesAction, Action noAction)
{
 
    TaskDialogButton yesButton = new("Yes") { Tag = DialogResult.Yes };
    TaskDialogButton noButton = new("No") { Tag = DialogResult.No };
 
    var buttons = new  TaskDialogButtonCollection
    {
        yesButton,
        noButton
    };
     
 
    TaskDialogPage page = new()
    {
        Caption = "Question",
        SizeToContent = true,
        Heading = heading,
        Icon = new  TaskDialogIcon(Properties.Resources.QuestionBlue),
        Buttons = buttons
    };
     
    var result = TaskDialog.ShowDialog(owner, page);
 
    if ((DialogResult)result.Tag == DialogResult.Yes)
    {
        yesAction?.Invoke();
    }
    else
    {
        noAction?.Invoke();
    }
     
}


In the above example clicking on the first button open a web page, in this case to Microsoft Doc's site.

/// <summary>
/// Example for opening a web page for windows forms
/// </summary>
/// <param name="owner">control or form</param>
public static  void OpenLink(Control owner)
{
    TaskDialogCommandLinkButton continueButton = new("&Quit", "Return to caller");
    TaskDialogCommandLinkButton linkButton = new("&Microsoft docs", "Open in default browser");
 
    linkButton.SetAddress("https://docs.microsoft.com/en-us/documentation/");
 
    linkButton.Click += LinkButtonClick;
 
    TaskDialogPage page = new()
    {
        Caption = "Question",
        Heading = "Open in browser",
        AllowCancel = true,
        Footnote = new  TaskDialogFootnote() { Text = $"Copyright {Now:yyyy}: Some company" },
        Buttons = { linkButton, continueButton }, 
        Icon = TaskDialogIcon.Information
    };
 
    TaskDialog.ShowDialog(owner,page);
 
}

How to use TaskDialog

Best way to use the code is to take the class project WindowsFormsLibrary, place it in a Visual Studio solution then build the solution.

For ease of use, redirect the build output to a library folder e.g. C:\DotNet\Libraries then when needed in a frontend project, add a reference to the dll. Alternate is to create a local NuGet package, add the local NuGet folder to NuGet package manager under Visual Studio and when needed install the package to a project.

Here the author  uses C:\OED\Dotnetland\NuGet for local packages.

Summary

This article has presented an enriched alternative to using a standard MessageBox to better present options to users along with better presentation overall. Not all examples have been laid out, there are many others to explore in the GitHub repository. 

See also

Windows Phone: Advanced MessageBox for Windows Phone
How to: Consistent modal message dialogs with C# and jQuery

Source code

Clone, fork or download from the following GitHub repository.