Dialogs

I l @ ve RuBoard

Dialogs come in two styles. The modal style requires that the user complete the actions on the dialog before returning to the normal flow of the application. Modeless, which is a simple fixed size window that can be used to perform some action, but leaves the user free to work on the main application too.

NOTE

Dialogs are best when they are simple. The design of a dialog is crucial to the usability of the application. Too many small dialogs can be annoying, especially if there is no choice of seeing them or not. Large dialogs, especially modal ones, are annoying because they require a lot of interaction that can break the flow of the application.


Dialogs under MFC were the usual odd mixture of Win32 API and object-oriented wrapper code, particularly in the Dialog Data eXchange or DDX system. This represented data in the dialog as data members of the dialog class, but used these members as a staging area for the real information that is edited or selected by the Windows controls on the dialog surface. This meant that there was no instant update mechanism for dialogs because data needed to be transferred to and from the dialog's child windows by the use of Windows messages. Dialogs under Windows Forms are different. They are, like the applications that host them, fully object- oriented components that work in a more logical manner.

Under .NET, dialogs are essentially Windows Forms. Controls are placed on them in the same way that you would build a form application ”with a tool or by coding directly.

Using the Common Dialogs

Common dialogs are simple to use and provide a consistent interaction with the underlying operating system. Dialogs are displayed with the ShowDialog function. All common dialogs are derived from the System.Windows.Forms.CommonDialog class. You can use this as a base class for custom dialogs that you might create.

The FileDialog Family

The most used of the common dialogs must be the file dialogs. Windows Forms defines a file- open and file-save dialog. To use these in your application, you need to put a member of type OpenFileDialog or SaveFileDialog in your application. Incidentally, both these dialogs are derived from System.Windows.Forms.FileDialog .

Listing 3.2.1 shows a simple application with a file-open dialog.

Listing 3.2.1 fileopen.cs : OpenFileDialog in Action
 1: using System;  2: using System.Drawing;  3: using System.ComponentModel;  4: using System.Windows.Forms;  5:  6:  7: namespace Sams  8: {  9: 10: class fileopenapp : System.Windows.Forms.Form 11: { 12: 13:     MainMenu m_menu; 14:     MenuItem m_filemenu; 15: 16:     void OnOpenFile(Object sender, EventArgs e) 17:     { 18:         OpenFileDialog dlg=new OpenFileDialog(); 19: 20:         if(dlg.ShowDialog() == DialogResult.OK) 21:         { 22:             MessageBox.Show("You selected the file "+dlg.FileName); 23:         } 24:     } 25: 26:     void OnExit(Object sender, EventArgs e) 27:     { 28:         Application.Exit(); 29:     } 30: 31:     fileopenapp() 32:     { 33:         m_menu = new MainMenu(); 34:         m_filemenu=new MenuItem("&File"); 35:         m_menu.MenuItems.Add(m_filemenu); 36:         MenuItem t; 37: 38:         t=new MenuItem("&Open"); 39:         t.Click += new EventHandler(OnOpenFile); 40:         m_filemenu.MenuItems.Add(t); 41: 42:         t=new MenuItem("-"); 43:         m_filemenu.MenuItems.Add(t); 44: 45:         t=new MenuItem("E&xit"); 46:         t.Click += new EventHandler(OnExit); 47:         m_filemenu.MenuItems.Add(t); 48: 49:         this.Menu = m_menu; 50:     } 51: 52:     public static void Main() 53:     { 54:         Application.Run(new fileopenapp()); 55:     } 56: } 57: 58: } // end of Sams namespace 

This example is the very simplest use of the dialog. Common dialogs provide much more functionality and are used in more complex ways.

A common dialog control is used differently when the application is constructed by Visual Studio.NET for example. In this instance, the application will instantiate a copy of the dialog when the application is run and attach an event source called FileOK to a button click handler in the form that uses the dialog. The delegate for this event handler is a little different from that of menu events. The signature for the CancelEventHandler is as follows :

 void FN(object sender, System.ComponentModel.CancelEventArgs e) 

Listing 3.2.2 shows the equivalent to this approach in a hand-built form.

Listing 3.2.2 fileopenevent.cs : Event-driven Common Dialog Response
 1: using System;  2: using System.Drawing;  3: using System.ComponentModel;  4: using System.Windows.Forms;  5: using System.IO;  6:  7:  8: namespace Sams  9: { 10: 11: class fileopenapp : System.Windows.Forms.Form 12: { 13: 14:     MainMenu m_menu; 15:     MenuItem m_filemenu; 16: 17:     OpenFileDialog openfiledlg1; 18: 19:     void OnOpenFile(Object sender, EventArgs e) 20:     { 21:         openfiledlg1.Filter = "C# files (*.cs)"+ 22:             "*.csBitmap files (*.bmp)*.bmp"; 23:         openfiledlg1.FilterIndex = 1; 24:         openfiledlg1.ShowDialog(); 25:     } 26: 27:     void OnExit(Object sender, EventArgs e) 28:     { 29:         Dispose(); 30:     } 31: 32:     fileopenapp() 33:     { 34:         m_menu = new MainMenu(); 35:         m_filemenu=new MenuItem("&File"); 36:         m_menu.MenuItems.Add(m_filemenu); 37:         MenuItem t; 38: 39:         t=new MenuItem("&Open"); 40:         t.Click += new EventHandler(OnOpenFile); 41:         m_filemenu.MenuItems.Add(t); 42: 43:         t=new MenuItem("-"); 44:         m_filemenu.MenuItems.Add(t); 45: 46:         t=new MenuItem("E&xit"); 47:         t.Click += new EventHandler(OnExit); 48:         m_filemenu.MenuItems.Add(t); 49: 50:         this.Menu = m_menu; 51: 52:         openfiledlg1 = new OpenFileDialog(); 53:         openfiledlg1.FileOk += new CancelEventHandler(OnFileOpenOK); 54:     } 55: 56:     void OnFileOpenOK(Object sender, CancelEventArgs e) 57:     { 58:         //MessageBox.Show("You selected the file "+openfiledlg1.FileName); 59:         // remember to add "using System.IO;" to the top of this file. 60:         OpenFileDialog dlg = (OpenFileDialog)sender; 61: 62:         Stream FileStream; 63:         if((FileStream = dlg.OpenFile())!=null) 64:         { 65:             //perform the read from FileStream here... 66:             FileStream.Close(); //and tidy up... 67:         } 68:     } 69: 70:     public static void Main() 71:     { 72:         Application.Run(new fileopenapp()); 73:     } 74: } 75: 76: } // end of Sams namespace 

The event in Listing 3.2.2 will only fire if the OK button has been clicked. There is also a HelpRequested event that will fire if the Help button in the dialog is chosen .

A file dialog can be made to present only a particular set of files by specifying a filter or even to open a file and return a file-stream for you. Lines 19 “25 of the listing show how a filter is set for a particular selection of file types.

Lines 56 “68 define the event handler that is triggered when a file is selected and opened using the dialog box.

Figure 3.2.1 shows a screen shot of FileOpenDialog as defined by this code.

Figure 3.2.1. The FileOpenDialog showing file filtering.

graphics/0302fig01.gif

SaveFileDialog works in a similar manner because it inherits most of its functionality from FileDialog . If you use the OpenFile function, a chosen file will be created or opened for writing.

NOTE

Note that FileDialog , OpenFileDialog , and SaveFileDialogs support properties that allow you to change the way files are displayed, checked, or selected. The .NET SDK help files should be consulted for details


The ColorDialog

Selecting color is a common function. Many people try to write color pickers themselves for reasons of aesthetics, but the Windows ColorDialog is simple to use and effective. What's more, it's consistent and familiar to most users.

Invoking ColorDialog is the same as other common dialogs by virtue of its base class. Create an instance of the class and call the ShowDialog method.

Figure 3.2.2 shows the ColorDialog in its various modes.

Figure 3.2.2. The ColorDialog in all its glory .

graphics/0302fig02.gif

The ColorDialog class returns color information in the form of a Color object. This contains the alpha, or transparency, and the red, green, and blue values of the color. There are also methods for ascertaining a color's hue, brightness, and saturation values.

There is a property called AllowFullOpen in the ColorDialog that allows you to decide if the Define Custom Colors button is enabled. You can also use the FullOpen property to force the complex color picker to appear. The CustomColors property is an array of color values that can be set or interrogated and that fill the custom color boxes on the control.

Listing 3.2.3 shows the ColorDialog in a selection of modes.

Listing 3.2.3 colordlgs.cs : Various Incarnations of the ColorDialog
 1: using System;  2: using System.Drawing;  3: using System.ComponentModel;  4: using System.Windows.Forms;  5:  6:  7: namespace Sams {  8:  9: 10: class ColorStretcher : System.Windows.Forms.Form 11: { 12: 13:     void OnFull(Object sender, EventArgs e) 14:     { 15:         ColorDialog dlg=new ColorDialog(); 16:         dlg.FullOpen = true; 17: 18:         dlg.ShowDialog(); 19:     } 20: 21:     void OnNoCustom(Object sender, EventArgs e) 22:     { 23:         ColorDialog dlg=new ColorDialog(); 24:         dlg.AllowFullOpen = false; 25: 26:         dlg.ShowDialog(); 27:     } 28: 29:     void OnNormal(Object sender, EventArgs e) 30:     { 31:         ColorDialog dlg=new ColorDialog(); 32:         dlg.Color = Color.PaleGoldenrod; 33:         dlg.ShowDialog(); 34:     } 35: 36:     void OnWithColours(Object sender, EventArgs e) 37:     { 38:         ColorDialog dlg=new ColorDialog(); 39:         dlg.FullOpen = true; 40:         // this statement defines the first five of the 41:         // custom color settings as ints the data is 42:         // 0xAARRGGBB where AA is alpha, RR is red, 43:         // GG is green and BB is blue expressed as the 44:         // hexadecimal byte equivalent 45:         dlg.CustomColors = new int[5]{ 0x00ff8040, 0x00c256fe, 46:                            0x00aa2005, 0x0004f002, 0x002194b5} ; 47: 48:         dlg.ShowDialog(); 49:     } 50: 51:     ColorStretcher() 52:     { 53:         // first a menu for the choices 54: 55:         MainMenu m=new MainMenu(); 56:         MenuItem top,temp; 57: 58:         top=new MenuItem("ColorDialog"); 59:         m.MenuItems.Add(top); 60: 61:         temp=new MenuItem("Full"); 62:         temp.Click+=new EventHandler(OnFull); 63:         top.MenuItems.Add(temp); 64: 65:         temp=new MenuItem("No custom"); 66:         temp.Click+=new EventHandler(OnNoCustom); 67:         top.MenuItems.Add(temp); 68: 69:         temp=new MenuItem("With Colours"); 70:         temp.Click+=new EventHandler(OnWithColours); 71:         top.MenuItems.Add(temp); 72: 73:         temp=new MenuItem("Normal"); 74:         temp.Click+=new EventHandler(OnNormal); 75:         top.MenuItems.Add(temp); 76: 77:         this.Menu = m; 78: 79:     } 80: 81:     public static void Main() 82:     { 83:         Application.Run(new ColorStretcher()); 84:     } 85: 86: } 87: } 

Notice how the custom colors are defined as integer values in the OnWithColours event handler (lines 36 “49).

To get the chosen color from the ColorDialog , simply read the contents of the Color property. Setting this property before invoking the ShowDialog method will pre-select a color. This is useful for changing colors that are already set in an application. This is shown in the OnNormal handler. To see the color selection, you must click the Define Custom Colors button. The color selected in the palette is the one that is programmed.

FontDialog

The font you choose for text is very important. Times Roman conveys a sense of solidity and reliability. Tahoma shows technical competence, Shotgun proves that you spent too much of your youth before 1975, and nothing says "I love you" better than 72-point Gigi.

The plethora of fonts available to the modern wordsmith is truly phenomenal, so there is nothing more important than a quick, simple method for choosing the face, size, and weight of a font. The standard font dialog is available to .Net programmers through the FontDialog class which, like its FileDialog and ColorDialog cousins, is derived from the CommonDialog class.

The technique for invoking the font dialog is the same as we have seen before. The properties of the dialog and the return data is uniquely dedicated to type face selection.

Listing 3.2.4 shows a simple application with a label and a font selection button. The button is wired to an event that invokes the font dialog. The font dialog itself has many options, set through its properties, that allow you to select the operations the dialog can perform. In the following example, we have enabled the Apply button and attached an event that updates the label text each time the Apply button is clicked.

Listing 3.2.4 fontdlg.cs : Using the Font Selection Dialog
 using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace Sams { class FontPicker : System.Windows.Forms.Form {   Button b;   Label l;   void OnApply(Object sender,System.EventArgs e)   {     FontDialog dlg = (FontDialog)sender;     l.Font=dlg.Font;   }   void OnClickedb(Object sender,EventArgs e)   {     // Create a new Font Dialog     FontDialog dlg=new FontDialog();     //Initialize it with the existing font in the label     dlg.Font = l.Font;     //Set the property to allow an "Apply button on the form"     dlg.ShowApply = true;     //attach an OnApply event handler     dlg.Apply += new EventHandler(OnApply);     if(dlg.ShowDialog() != DialogResult.Cancel)     {       l.Font = dlg.Font;     }   } public FontPicker()   {     this.Size=new Size(416,320);     l=new Label();     l.Location = new Point(8,8);     l.Size = new Size(400,200);     l.Text = "0 1 2 3 4 5 6 7 8 9 \ nabcdefghijklmnopqrstuvwxyz"+     "\ nABCDEFGHIJKLMNOPQRSTUVWXYZ";     l.Font = new Font("Microsoft Sans Serif", 18f);     this.Controls.Add(l);     b=new Button();     b.Text = "Choose Font";     b.Click += new EventHandler(OnClickedb);     b.Location = new Point(8,250);     b.Size = new Size(400,32);     this.Controls.Add(b);   }   static void Main()   {     Application.Run(new FontPicker());   } } } 

Build this file with the command line:

 csc /t:winexe fontdlg.cs 

The Print and Print Preview Dialogs

Rendering a document onscreen or to the printer requires graphics knowledge that we will cover more in depth later in this book, so we wont go into great detail on that subject at this stage. Just to give you a feel for print and print preview. In Listing 3.2.5 we have created a very simple application that enables you to perform print and print preview.

Listing 3.2.5 printpreview.cs Printing and Print Preview in Action
 Totally re-written...  1: namespace Sams   2: {   3:     using System;   4:     using System.Drawing;   5:     using System.Drawing.Printing;   6:     using System.Collections;   7:     using System.ComponentModel;   8:     using System.Windows.Forms;   9:  10:  11:     /// <summary>  12:     ///the ppView is a simple control window that uses a common draw  13:     ///method for both painting on screen and printing or print preview  14:     /// </summary>  15:     public class ppView : System.Windows.Forms.Panel  16:   {  17:     private ArrayList points;  18:  19:     Point mousePoint;  20:  21:  22:     void OnClick(Object sender, MouseEventArgs e)  23:     {  24:       if(points == null)  25:       {  26:         points=new ArrayList();  27:       }  28:  29:       points.Add(mousePoint);  30:       Invalidate();  31:     }  32:  33:     void OnMouseMove(Object sender,MouseEventArgs e)  34:     {  35:       mousePoint = new Point(e.X,e.Y);  36:     }  37:  38:     public ppView()  39:         {  40:       this.MouseDown+=new MouseEventHandler(OnClick);  41:       this.MouseMove+=new MouseEventHandler(OnMouseMove);  42:       this.BackColor=Color.White;  43:         }  44:  45:     private void DrawSmiley(Point pt, Graphics g)  46:     {  47:       g.FillEllipse(Brushes.Black,pt.X-52,pt.Y-52,104,104);  48:       g.FillEllipse(Brushes.Yellow,pt.X-50,pt.Y-50,100,100);  49:       g.FillEllipse(Brushes.Black,pt.X-30,pt.Y-10,60,40);  50:       g.FillEllipse(Brushes.Yellow,pt.X-35,pt.Y-10,70,35);  51:       g.FillEllipse(Brushes.Black,pt.X-25,pt.Y-15,10,10);  52:       g.FillEllipse(Brushes.Black,pt.X+10,pt.Y-15,10,10);  53:     }  54:  55:     private void DoDraw(Graphics g)  56:     {  57:       if(points == null)  58:       {  59:         return;  60:       }  61:       foreach(Point p in points)  62:       {  63:         DrawSmiley(p,g);  64:       }  65:     }  66:  67:     protected override void OnPaint(PaintEventArgs e)  68:     {  69:       if(points == null)  70:       {  71:         return;  72:       }  73:       DoDraw(e.Graphics);  74:     }  75:  76:     public void OnPrintPage(Object sender,PrintPageEventArgs e)  77:     {  78:       if(points == null)  79:       {  80:         return;  81:       }  82:       DoDraw(e.Graphics);  83:     }  84:     }  85:  86:  87:     /// <summary>  88:     ///    This is the application that hosts the MainApps.  89:     /// </summary>  90:     public class MDIChildForm : System.Windows.Forms.Form  91:     {  92:         /// <summary>  93:         ///    Required designer variable.  94:         /// </summary>  95:         private System.ComponentModel.Container components;  96:     private ppView vw;  97:  98:     // Accessor for private data  99:     public ppView View { 100:       get 101:       { 102:         return vw; 103:       } 104:     } 105: 106:     public MDIChildForm() 107:         { 108: 109: 110:             // 111:             // Required for Windows Form Designer support 112:             // 113:             InitializeComponent(); 114: 115:       vw=new ppView(); 116:       vw.Location = new Point(3,3); 117:       vw.Size = new Size(this.Size.Width-6,this.Size.Height-6); 118:       vw.Anchor=AnchorStyles.Left 119:               AnchorStyles.Top 120:               AnchorStyles.Right 121:               AnchorStyles.Bottom; 122: 123:       this.Controls.Add(vw); 124: 125:       // 126:       // TODO: Add any constructor code after InitializeComponent call 127:       // 128:         } 129: 130:         /// <summary> 131:         ///    Clean up any resources being used. 132:         /// </summary> 133:         public override void Dispose() 134:         { 135:             base.Dispose(); 136:             components.Dispose(); 137:         } 138: 139:         /// <summary> 140:         ///    Required method for Designer support - do not modify 141:         ///    the contents of this method with the code editor. 142:         /// </summary> 143:         private void InitializeComponent() 144:     { 145:       this.components = new System.ComponentModel.Container (); 146:       this.Text = "MDIChildForm"; 147:       this.AutoScaleBaseSize = new System.Drawing.Size (5, 13); 148:       this.ClientSize = new System.Drawing.Size (328, 277); 149:     } 150:     } 151: 152:     /// <summary> 153:     ///    Summary description for MainApp. 154:     /// </summary> 155:     public class MainApp : System.Windows.Forms.Form 156:     { 157:         /// <summary> 158:         ///    Required designer variable. 159:         /// </summary> 160:         private System.ComponentModel.Container components; 161:     private System.Windows.Forms.MenuItem FileExit; 162:     private System.Windows.Forms.MenuItem FilePrintPreview; 163:     private System.Windows.Forms.MenuItem FilePrint; 164:     private System.Windows.Forms.MenuItem FileNew; 165:     private System.Windows.Forms.MenuItem menuItem1; 166:     private System.Windows.Forms.MainMenu mainMenu1; 167: 168:         public MainApp() 169:         { 170:             // 171:             // Required for Windows Form Designer support 172:             // 173:             InitializeComponent(); 174: 175:             // 176:             // Add any constructor code after InitializeComponent call 177:             // 178:         } 179: 180:         /// <summary> 181:         ///    Clean up any resources being used. 182:         /// </summary> 183:         public override void Dispose() 184:         { 185:             base.Dispose(); 186:             components.Dispose(); 187:         } 188: 189:         /// <summary> 190:         ///    Required method for Designer support - do not modify 191:         ///    the contents of this method with the code editor. 192:         /// </summary> 193:         private void InitializeComponent() 194:     { 195:       this.components = new System.ComponentModel.Container (); 196:       this.mainMenu1 = new System.Windows.Forms.MainMenu (); 197:       this.FilePrintPreview = new System.Windows.Forms.MenuItem (); 198:       this.FileExit = new System.Windows.Forms.MenuItem (); 199:       this.menuItem1 = new System.Windows.Forms.MenuItem (); 200:       this.FileNew = new System.Windows.Forms.MenuItem (); 201:       this.FilePrint = new System.Windows.Forms.MenuItem (); 202:       mainMenu1.MenuItems.AddRange( 203:         new System.Windows.Forms.MenuItem[1] { this.menuItem1} ); 204:       FilePrintPreview.Text = "P&review..."; 205:       FilePrintPreview.Index = 2; 206:       FilePrintPreview.Click += 207:         new System.EventHandler (this.FilePrintPreview_Click); 208:       FileExit.Text = "&Exit"; 209:       FileExit.Index = 3; 210:       FileExit.Click += new System.EventHandler (this.FileExit_Click); 211:       menuItem1.Text = "&File"; 212:       menuItem1.Index = 0; 213:       menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[4] 214:                 { this.FileNew, 215:          this.FilePrint, 216:          this.FilePrintPreview, 217:          this.FileExit} ); 218:       FileNew.Text = "&New"; 219:       FileNew.Index = 0; 220:       FileNew.Click += new System.EventHandler (this.FileNew_Click); 221:       FilePrint.Text = "&Print..."; 222:       FilePrint.Index = 1; 223:       FilePrint.Click += new System.EventHandler (this.FilePrint_Click); 224:       this.Text = "MainApp"; 225:       this.AutoScaleBaseSize = new System.Drawing.Size (5, 13); 226:       this.IsMdiContainer = true; 227:       this.Menu = this.mainMenu1; 228:       this.ClientSize = new System.Drawing.Size (368, 289); 229:     } 230: 231:     protected void FileExit_Click (object sender, System.EventArgs e) 232:     { 233:       Application.Exit(); 234:     } 235: 236:     protected void FilePrintPreview_Click(object sender, System.EventArgs e) 237:     { 238:       PrintPreviewDialog d=new PrintPreviewDialog(); 239:       PrintDocument doc = new PrintDocument(); 240: 241:       MDIChildForm f = (MDIChildForm)this.ActiveMdiChild; 242:       ppView vw = f.View; 243:       doc.PrintPage += new PrintPageEventHandler(vw.OnPrintPage); 244: 245:       d.Document=doc; 246: 247:       d.ShowDialog(); 248: 249:       doc.PrintPage -= new PrintPageEventHandler(vw.OnPrintPage); 250:     } 251: 252:     protected void FilePrint_Click (object sender, System.EventArgs e) 253:     { 254:       PrintDialog dlg = new PrintDialog(); 255:       PrintDocument doc = new PrintDocument(); 256: 257:       MDIChildForm f = (MDIChildForm)this.ActiveMdiChild; 258:       ppView vw = f.View; 259:       doc.PrintPage += new PrintPageEventHandler(vw.OnPrintPage); 260: 261:       dlg.Document=doc; 262: 263:       dlg.ShowDialog(); 264: 265:       doc.PrintPage -= new PrintPageEventHandler(vw.OnPrintPage); 266: 267:     } 268: 269:     protected void FileNew_Click (object sender, System.EventArgs e) 270:     { 271:       MDIChildForm f = new MDIChildForm(); 272:       f.MdiParent=this; 273:       f.Show(); 274:     } 275: 276:         /// <summary> 277:         /// The main entry point for the application. 278:         /// </summary> 279:         public static void Main(string[] args) 280:         { 281:             Application.Run(new MainApp()); 282:         } 283:     } 284: } 

This application has three components. The form, called MainApp , is a Multiple Document Interface (MDI) application and hosts a number of MDIChildForm objects. These, in turn , host a simple control called ppView .

The ppView does all the work of tracking the mouse, adding simple points to an array list, and drawing smiley faces at every stored point. It also employs the technique of a single, simple draw routine that takes a Graphics object as an argument.

The print and print preview mechanism uses a PrintDocument that fires an event for each printed page. To use the print preview and print facilities, the simple draw routine is used by the OnPaint , line 67, and the OnPrintPage , line 76, events that call the DoDraw method with whatever drawing device context they have been given by the screen or printer drivers. The Graphics context passed to the DoDraw routine when drawing onscreen is different than when printing. The drawing system knows that it needs to change scales and pixel resolution for you, depending on the device.

If you're interested in the graphics used, lines 47 “52 draw the smileys.

I l @ ve RuBoard


C# and the .NET Framework. The C++ Perspective
C# and the .NET Framework
ISBN: 067232153X
EAN: 2147483647
Year: 2001
Pages: 204

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net