Dialog Boxes
A dialog box is a form used to solicit input from a user. Dialog boxes, or simply dialogs, as they are often called, come in two styles: modal and modeless. When a modal dialog is displayed, its owner, which is typically the application s main form, is temporarily disabled. The Open File dialog featured in countless Windows applications is an example of a modal dialog. Modeless dialogs don t disable their owners; users are free to click back to the main form at any time. The Find and Replace dialog in Microsoft Word is an example of a modeless dialog.
To a developer versed in programming Windows using the Windows API, dialog boxes are special creatures that are just different enough from ordinary windows to be a bit of a nuisance. In Windows Forms, dialog boxes are nothing special; they re just forms. Literally. In fact, just three characteristics differentiate a dialog box from an ordinary form:
Dialogs have slightly different styles than ordinary forms. For example, dialogs rarely have minimize and maximize buttons, so most dialog constructors set the form s MinimizeBox and MaximizeBox properties to false.
Dialogs generally have OK and Cancel buttons. A couple of lines of code in a Windows Forms dialog identifies these buttons to the framework and enables the framework to automatically dismiss the dialog when either button is clicked.
To show an ordinary form, you call its Show method. To display a modal dialog, you call ShowDialog.
Experienced Windows developers are often shocked to find that Windows Forms dialogs create their controls programmatically. Traditional Windows applications use dialog resources that enable a dialog to be created, controls and all, with a simple function call. Windows Forms doesn t use dialog resources, so every dialog class contains code to create each and every control that it hosts.
Windows features an assortment of so-called system dialogs or common dialogs that developers can use to display Open File dialogs, Print dialogs, and other types of dialogs that are commonly found in Windows applications. The FCL wraps the common dialogs with easy-to-use classes. The following table lists the common dialog classes. All are defined in System.Windows.Forms. You ve seen one of these dialogs OpenFileDialog already in this chapter s ImageView application. Use these classes whenever appropriate to save on development time and give your Windows Forms applications a look and feel that is consistent with other Windows applications.
Class | Dialog Type |
ColorDialog | Color dialog boxes for choosing colors |
FontDialog | Font dialog boxes for choosing fonts |
OpenFileDialog | Open File dialog boxes for choosing files |
PageSetupDialog | Page Setup dialog boxes for entering page setup parameters |
PrintDialog | Print dialog boxes for entering print parameters |
SaveFileDialog | Save File dialog boxes for entering file names |
The DialogDemo Application
Figure 4-22 contains the source code for a simple Windows Forms application that displays a dialog box in response to a menu command. To display the dialog, select the Edit Ellipse command from the Options menu. In the dialog are controls that you can use to change the width and height of the ellipse in the application s main form. (See Figure 4-21.) You can also select the system of units inches, centimeters, or pixels that the width and height are measured in.
DialogDemo s dialog class is named MyDialog. Code in the class constructor initializes the dialog s properties. The first statement sizes the dialog:
ClientSize = new Size (296, 196);
The second statement sets the dialog s StartPosition property to FormStartPosition.CenterParent, which centers the dialog in the parent form each time it s displayed:
StartPosition = FormStartPosition.CenterParent;
The next statement gives the dialog a fixed dialog border, which prevents the dialog from being resized:
FormBorderStyle = FormBorderStyle.FixedDialog;
The next two statements remove the minimize and maximize buttons that appear in the dialog s title bar by default, and the statement after that sets the text in the dialog s title bar:
MaximizeBox = false; MinimizeBox = false; Text = "Edit Ellipse";
The final statement prevents the dialog from causing a button to appear in the system s task bar:
ShowInTaskbar = false;
Top-level forms should appear in the task bar, but dialog boxes should not.
Most of the remaining code in MyDialog s constructor creates the dialog s controls and adds them to the Controls collection. But notice these two statements:
AcceptButton = OKButton; CancelButton = NotOKButton;
AcceptButton and CancelButton are properties that MyDialog inherits from Form. AcceptButton identifies the dialog s OK button; CancelButton identifies the Cancel button. OK and Cancel buttons are special because they dismiss the dialog box that is, cause it to disappear from the screen. The statements above identify the OK and Cancel buttons to the framework so that it can dismiss the dialog when either button is clicked.
The following statements instantiate and display the dialog:
MyDialog dlg = new MyDialog (); . . . if (dlg.ShowDialog (this) == DialogResult.OK) {
The dialog appears on the screen when ShowDialog is called. ShowDialog is a blocking call; it doesn t return until the dialog is dismissed. Its return value tells you how the dialog was dismissed. DialogResult.OK means the user clicked the OK button. DialogResult.Cancel means the user clicked Cancel. Most applications ignore what was entered into the dialog if the Cancel button is clicked. DialogDemo discards the input if ShowDialog s return value is anything other than DialogResult.OK, which means the user can cancel out of the dialog without affecting the ellipse in any way.
MyDialog exposes the input that the user enters through public properties named UserWidth, UserHeight, and UserUnits. When read, these properties extract data from the dialog s controls. When written to, they transfer data to the controls. Before calling ShowDialog to display the dialog, DialogDemo initializes the dialog s controls by initializing the corresponding properties:
dlg.UserWidth = MyWidth; dlg.UserHeight = MyHeight; dlg.UserUnits = (int) MyUnits;
And when the dialog is dismissed (provided it s dismissed with the OK button), DialogDemo extracts the user input by reading MyDialog property values:
MyWidth = dlg.UserWidth; MyHeight = dlg.UserHeight; MyUnits = (MyForm.Units) dlg.UserUnits;
Thus, public properties in the dialog class serve as a mechanism for transferring data to and from the dialog s controls. This mechanism is typically how Windows Forms applications get data in and out of dialogs.
Figure 4-21
DialogDemo in action.
DialogDemo.cs
using System; using System.Windows.Forms; using System.Drawing; class MyForm : Form { enum Units { Inches, Centimeters, Pixels } int MyWidth = 400; int MyHeight = 200; Units MyUnits = Units.Pixels;
MyForm () { // Set the form's title Text = "Dialog Demo"; // Set the form's size ClientSize = new Size (640, 480); // Create a menu MainMenu menu = new MainMenu (); MenuItem item = menu.MenuItems.Add ("&Options"); item.MenuItems.Add ("Edit Ellipse...", new EventHandler (OnEditEllipse)); item.MenuItems.Add ("-"); item.MenuItems.Add ("E&xit", new EventHandler (OnExit)); // Attach the menu to the form Menu = menu; } // Handler for the Edit Ellipse command void OnEditEllipse (object sender, EventArgs e) { // Create the dialog MyDialog dlg = new MyDialog (); // Initialize the dialog dlg.UserWidth = MyWidth; dlg.UserHeight = MyHeight; dlg.UserUnits = (int) MyUnits; // Display the dialog if (dlg.ShowDialog (this) == DialogResult.OK) { // If the dialog was dismissed with the OK button, // extract the user input and repaint the form MyWidth = dlg.UserWidth; MyHeight = dlg.UserHeight; MyUnits = (MyForm.Units) dlg.UserUnits; Invalidate (); } // Dispose of the dialog dlg.Dispose (); } // Handler for the Exit command void OnExit (object sender, EventArgs e) { Close (); } // OnPaint handler protected override void OnPaint (PaintEventArgs e) { int multiplier = 1; switch (MyUnits) { case Units.Inches: e.Graphics.PageUnit = GraphicsUnit.Inch; break; case Units.Centimeters: e.Graphics.PageUnit = GraphicsUnit.Millimeter; multiplier = 10; break; case Units.Pixels: e.Graphics.PageUnit = GraphicsUnit.Pixel; break; } SolidBrush brush = new SolidBrush (Color.Magenta); e.Graphics.FillEllipse (brush, 0, 0, MyWidth * multiplier, MyHeight * multiplier); brush.Dispose (); } static void Main () { Application.Run (new MyForm ()); } } class MyDialog : Form { Label WidthLabel; Label HeightLabel; TextBox WidthBox; TextBox HeightBox; GroupBox UnitsGroup; RadioButton InchesButton; RadioButton CentimetersButton; RadioButton PixelsButton; Button OKButton; Button NotOKButton; public int UserWidth { get { return Convert.ToInt32 (WidthBox.Text); } set { WidthBox.Text = value.ToString (); } } public int UserHeight { get { return Convert.ToInt32 (HeightBox.Text); } set { HeightBox.Text = value.ToString (); } } public int UserUnits { get { for (int i=0; i<UnitsGroup.Controls.Count; i++) { RadioButton button = (RadioButton) UnitsGroup.Controls[i]; if (button.Checked) return i; } return -1; } set { RadioButton button = (RadioButton) UnitsGroup.Controls[value]; button.Checked = true; } } public MyDialog () { // Initialize the dialog's visual properties ClientSize = new Size (296, 196); StartPosition = FormStartPosition.CenterParent; FormBorderStyle = FormBorderStyle.FixedDialog; MaximizeBox = false; MinimizeBox = false; Text = "Edit Ellipse"; ShowInTaskbar = false; // Create the dialog's controls WidthLabel = new Label (); WidthLabel.Location = new Point (16, 16); WidthLabel.Size = new Size (48, 24); WidthLabel.Text = "Width"; HeightLabel = new Label (); HeightLabel.Location = new Point (16, 48); HeightLabel.Size = new Size (48, 24); HeightLabel.Text = "Height"; WidthBox = new TextBox (); WidthBox.Location = new Point (64, 12); WidthBox.Size = new Size (96, 24); WidthBox.TabIndex = 1; HeightBox = new TextBox (); HeightBox.Location = new Point (64, 44); HeightBox.Size = new Size (96, 24); HeightBox.TabIndex = 2; UnitsGroup = new GroupBox (); UnitsGroup.Location = new Point (16, 76); UnitsGroup.Size = new Size (144, 100); UnitsGroup.Text = "Units"; InchesButton = new RadioButton (); InchesButton.Location = new Point (16, 24); InchesButton.Size = new Size (112, 16); InchesButton.Text = "Inches"; CentimetersButton = new RadioButton (); CentimetersButton.Location = new Point (16, 48); CentimetersButton.Size = new Size (112, 16); CentimetersButton.Text = "Centimeters"; PixelsButton = new RadioButton (); PixelsButton.Location = new Point (16, 72); PixelsButton.Size = new Size (112, 16); PixelsButton.Text = "Pixels"; OKButton = new Button (); OKButton.Location = new Point (184, 12); OKButton.Size = new Size (96, 24); OKButton.TabIndex = 3; OKButton.Text = "OK"; OKButton.DialogResult = DialogResult.OK; NotOKButton = new Button (); NotOKButton.Location = new Point (184, 44); NotOKButton.Size = new Size (96, 24); NotOKButton.TabIndex = 4; NotOKButton.Text = "Cancel"; NotOKButton.DialogResult = DialogResult.Cancel; AcceptButton = OKButton; CancelButton = NotOKButton; // Add the controls to the dialog Controls.Add (WidthLabel); Controls.Add (HeightLabel); Controls.Add (WidthBox); Controls.Add (HeightBox); Controls.Add (UnitsGroup); UnitsGroup.Controls.Add (InchesButton); UnitsGroup.Controls.Add (CentimetersButton); UnitsGroup.Controls.Add (PixelsButton); Controls.Add (OKButton); Controls.Add (NotOKButton); } }Figure 4-22
The DialogDemo source code.