Dot Net Perls

Customized Dialog Box in C#

by Sam Allen - Updated June 13, 2009

Problem. You want to build a custom dialog in Windows Forms that is polished and professional, and also complies with Microsoft's UI guidelines. MessageBox doesn't adhere to the guidelines. Solution. Here we have sample code for the customized dialog box. You can use the new dialog in your programs just as easily as you can use MessageBox.Show.

Dialog box

1. Implementing ShowDialog

Here we can use a special static method. It has a private constructor, so all you have to do is call its public method called ShowDialog. The following code sample is part of the code of the custom dialog. Here we implement ShowDialog, and then call it.

/// <summary>
/// This method is part of the dialog, and provides a static calling method.
/// </summary>
static public DialogResult ShowDialog(string title, string largeHeading,
    string smallExplanation, string leftButton, string rightButton,
    Image iconSet)
{
    // Call the private constructor so the users only need to call this
    // function, which is similar to MessageBox.Show.
    // Returns a standard DialogResult.
    using (BetterDialog dialog = new BetterDialog(title, largeHeading,
        smallExplanation, leftButton, rightButton, iconSet))
    {
        DialogResult result = dialog.ShowDialog();
        return result;
    }
}

/// <summary>
/// This is the calling convention of the above method.
/// Use this to show a custom dialog in your source code.
/// </summary>
private void ExampleCall()
{
    DialogResult result = BetterDialog.ShowDialog("Reset Journal Settings",
        "Settings will be erased permanently",
        "This will not affect any of the text content in the database, but....",
        "Reset", "Cancel", Properties.Resources.DialogWarningXP);

    if (result == DialogResult.OK)
    {
        Console.WriteLine("User accepted the dialog");
    }
}

2. The internal dialog logic

The following code sample implements the basic logic, but lacks many of the details in my implementation. If you are reading this page, you may not need those details. If you are writing your own dialog, you can see some of the logic and method calls used and the general technique.

/// <summary>
/// Use this with the above static method. This is how the dialog is created.
/// I provide this code to show some implementation details. If you want the
/// full, working code, download the archive.
/// </summary>
private BetterDialog(string title, string largeHeading, string smallExplanation,
    string leftButton, string rightButton, Image iconSet)
{
    // Set up some properties.
    this.Font = SystemFonts.MessageBoxFont;
    this.ForeColor = SystemColors.WindowText;
    InitializeComponent();
    this.Width = 350;
    this.Height = 150;

    // Do some measurements with Graphics.
    using (Graphics graphics = this.CreateGraphics())
    {
        SizeF smallSize;
        SizeF bigSize;

        if (string.IsNullOrEmpty(smallExplanation) == false)
        {
            // Note: at this point, we could detect that the OS is Vista
            // and do some customizations. That logic is in the download.
            // The code here does some measurements.
            label1.Font = new Font(SystemFonts.MessageBoxFont.FontFamily.Name, 8.0f,
                FontStyle.Bold, GraphicsUnit.Point);
            smallSize = graphics.MeasureString(smallExplanation, this.Font,
                this.label2.Width);
            bigSize = graphics.MeasureString(largeHeading, label1.Font,
                this.label1.Width);
            this.Height = (int)smallSize.Height + 166;
            double bigger = (smallSize.Width > bigSize.Width) ?
                smallSize.Width : bigSize.Width;
            this.Width = (int)bigger + 100;
        }
        else
        {
            // We have a null "smallExplanation", so we have a single message
            // dialog. Do some different changes. Code omitted for brevity (you
            // can find the logic in the download if you want to see it).
        }
    }

    // Establish a minimum width.
    if (this.Width < 260)
    {
        this.Width = 260;
    }

    // Set the title, and some Text properties.
    this.Text = title;
    label1.Text = largeHeading;
    label2.Text = string.IsNullOrEmpty(smallExplanation) ?
        string.Empty : smallExplanation;

    // Set the left button, which is optional.
    if (string.IsNullOrEmpty(leftButton) == false)
    {
        this.buttonLeft.Text = leftButton;
    }
    else
    {
        this.AcceptButton = buttonRight;
        this.buttonLeft.Visible = false;
    }
    this.buttonRight.Text = rightButton;

    // Set the PictureBox and the icon.
    pictureBox1.Image = iconSet;
}

3. Properties on the dialog

Here we see some of the special attributes this dialog has. The custom dialog has the following properties, many of which are not in the default MessageBox in Windows Forms .NET. [C# MessageBox.Show Examples in Windows Forms - dotnetperls.com]

4. Designer view in Visual Studio

Here is a picture of the form in the Visual Studio 2008 Designer. You can see the basic layout, with two TableLayoutPanel controls and the PictureBox. This is the basic skeleton of the custom dialog that the logic uses to construct and measure the final window. The complete logic is about 180 lines of C# code.

Dialog designer view

5. Conclusion

Here we saw an example of a custom dialog in C#. Unfortunately, there are some weaknesses here. It can look odd in real edge-cases, such as a dialog with the text of War and Peace in it. Rigorously test your code to make sure it doesn't embarrass you down the line.

Dot Net Perls
Windows Forms | BackgroundWorker Tutorial | ContextMenuStrip Example | DataGridView Tips and Secrets | DataGridView Tutorial | MessageBox.Show Examples in...
C# | Dictionary StringComparer Tip | DateTime.TryParse Example | Reflection Field Example | Validate Characters in String
© 2009 Sam Allen. All rights reserved.