Using CommonDialogControls The Bell Ringers application now allows you to save information, but it always saves data to the same file, overwriting anything that is already there. Also, the print functionality is still missing. Now is the time to address these issues. There are a number of everyday tasks that require the user to specify some sort of information. For example, if the user wants to print a file, the user is usually asked which printer to use, and the user can set additional properties such as the number of copies. You might have noticed that the same Print dialog box is used by many different applications. This is not due to lack of imagination by applications developers; it is just that the requirement is so common that Microsoft has standardized it and made it available as a “common dialog”—a component supplied with the Microsoft Windows operating system that you can use in your own applications. There are a number of other commondialog boxes available as well, including dialog boxes for opening and saving files, selecting colors and fonts, specifying page formats, and performing print previews. You can use any of these commondialog boxes in Visual Studio 2005 through the commondialog controls. Using the SaveFileDialog Control In the following exercise, you will use the SaveFileDialog control. In the BellRingers application, when the user saves details to a file you will prompt the user for the name and location of the file by using a SaveFileDialog control. Use a SaveFileDialog control 1. Display MemberForm in the Design View window. 2. In the Toolbox, expand the Dialogs category. 3. Drag a SaveFileDialog control onto the form. The control appears under the form and is given the name saveFileDialog1. 4. Click the saveFileDialog1 control. In the Properties window, set its properties by using the values specified in the following table. Property Value Description (Name) saveFileDialog The name of the control. AddExtension True Setting this property to True allows the dialog box to add the file extension indicated by the Property Value Description DefaultExt property to the name of the file specified by the user if the user omits the file extension. DefaultExt txt The default file extension to use if the user does not specify the extension when providing the filename. FileName Leave blank The name of the currently selected file. Delete the value if you don't want a file to be selected by default. InitialDirectory C:\ The default directory to be used by the dialog box. OverwritePrompt True If this property is True, the user is warned when an attempt is made to overwrite an existing file with the same name. For this to work, the ValidateNames property must also be set to True. Title Bell Ringers A string that is displayed on the title bar of the dialog box. ValidateNames True This property indicates whether filenames are validated. It is used by some other properties, such as OverwritePrompt. If this property is set to True, the dialog box also checks to verify that any filename typed in by the user contains only valid characters. 5. In the Code And Text Editor window displaying MemberForm.cs, locate the saveMemberClick method at the end of the file. 6. Type the following statements at the start of this method, surrounding the code that creates and uses the StreamWriter object: 7. DialogResult buttonClicked = saveFileDialog.ShowDialog(); 8. if (buttonClicked.Equals(DialogResult.OK)) 9. { 10. StreamWriter writer = new StreamWriter("Members.txt"); // existing code 11. . 12. MessageBox.Show("Member details saved", "Saved"); // existing code } 13. The first statement displays the Save File dialog box by using the ShowDialog method. The Save File dialog box is modal, which means that the user cannot continue using any other forms in the application until she has closed this dialog box by clicking one of its buttons. Modal dialog boxes also have a DialogResult property that indicates which button the user clicked (the Save dialog has a Save button and a Cancel button). The ShowDialog method returns the value of this DialogResult property; if the user clicks Save, the DialogResult property will be OK (not Save because there is no such DialogResult value). IMPORTANT The SaveFileDialog control prompts the user for the name of a file to save to, but does not actually do any saving—you still have to supply that code yourself. 14. Modify the statement that creates the StreamWriter object: StreamWriter writer = new StreamWriter(saveFileDialog.FileName); The method will now write to the file specified by the user rather than Members.txt. 15. Build and run the application. Create a new member. On the File menu, click Save Member. The Bell Ringers dialog box opens and you are asked for the name of the file you want to save. If you omit the file extension, “.txt” is added automatically when the file is saved. If you pick an existing file, the dialog box warns you before it closes. 16. When you have finished, close the application. You can use a similar technique for opening a file; add an OpenFileDialog control to the form, invoke it by using the ShowDialog method, and retrieve the FileName property when the method returns if the user has clicked the Open button. You can then open the file, read its contents, and populate the fields on the screen. For more details on using the OpenFileDialog control, consulting the MSDN Library for Visual Studio 2005. Using a Printer Printing is another common requirement of professional Windows applications. Visual Studio provides controls that can help you send data to a printer very quickly and easily. One of these controls is another CommonDialog that allows the user to specify the printer to use. Additionally, the PrintDocument control allows the programmer to manipulate the data being sent to the printer. In the final exercise in this chapter, you will implement the Print menu command, making use of the PrintDialog and PrintDocument controls. Use a PrintDialog control 1. Display MemberForm in the Design View window. 2. In the Toolbox, expand the Printing category. 3. Drag a PrintDialog control onto the form. The control appears under the form and is given the name printDialog1. 4. Click the printDialog1 control. In the Properties window, change the (Name) property to printDialog. 5. On MemberForm, click the File menu, and then click Print. 6. Click the Events button in the Properties window. Select the Click event, type printClick, and then press Enter. 7. In the Code And Text Editor window, add the following statements to the printClick method: 8. DialogResult buttonClicked = printDialog.ShowDialog(); 9. if (buttonClicked.Equals(DialogResult.OK)) 10. { 11. // You will write this code shortly } This is the same idiom that you saw earlier, when using the SaveFileDialog control. Use a PrintDocument control 1. Return to the Design View window. 2. Click and drag a PrintDocument control from the Printing category in the Toolbox onto MemberForm. Another control appears under the form, called printDocument1. 3. Using the Properties window, change the name of this control to printDocument. Clear the DocumentName property. 4. Click the printDialog control. In the Properties window, set the Document property of this control to printDocument. This is necessary as the printDialog control uses the printDocument control to obtain printer settings. 5. Switch back to the Code And Text Editor displaying MemberForm.cs, and return to the printClick method. 6. Replace the comment in the middle of this method with the following statement: printDocument.Print(); This statement starts the printing process on the selected printer. However, you still need to do some work; you must format the data to be printed by using the PrintPage event of the printDocument control. 7. In the Design View window, click the printDocument control. Click the Events button in the Properties window. Select the PrintPage event, type printPage, and then press Enter. 8. In the Code And Text Editor window, add the following statements to the printPage method: 9. StringBuilder data = new StringBuilder(); 10. 11. StringWriter writer = new StringWriter(data); 12. writer.WriteLine("First Name: " + firstName.Text); 13. writer.WriteLine("Last Name: " + lastName.Text); 14. writer.WriteLine("Tower: " + towerNames.Text); 15. writer.WriteLine("Captain: " + isCaptain.Checked); 16. writer.WriteLine("Member Since: " + memberSince.Text); 17. writer.WriteLine("Methods: "); 18. foreach (object methodChecked in methods.CheckedItems) 19. { 20. writer.WriteLine(methodChecked.ToString()); 21. } writer.Close(); You should recognize much of this code as it is very similar to the logic used when saving a member's data to a file. The StringWriter class is another stream-oriented class, much like StreamWriter that you saw earlier in this chapter. It supports many of the same methods and properties. The only real difference is that it sends its data to a StringBuilder object rather than a file. The StringBuilder class provides a very efficient way for creating and manipulating strings. It has many of the same features as the string type, but also allows you to easily add and remove characters in a string. By the end of this block of code, the data variable contains the information ready to be sent to the printer. NOTE In the .NET Framework and C#, the string data type is immutable; when you modify the value in a string, the runtime actually creates a new string containing the modified value, and then discards the old string. Repeatedly modifying a string can cause your code to become inefficient as a new string has to be created in memory at each change (the old string will eventually be garbage collected). The StringBuilder class, in the System.Text namespace, is designed to avoid this inefficiency. You can add and remove characters from a StringBuilder object using the Append, Insert, and Remove methods without creating a new object each time. 22. Append the following statements to the end of the printPage method: 23. float leftMargin = e.MarginBounds.Left; 24. float topMargin = e.MarginBounds.Top; 25. float yPos = 0; 26. Font printFont = null; 27. 28. printFont = new Font("Arial", 12); 29. yPos = topMargin + printFont.GetHeight(e.Graphics); 30. e.HasMorePages = false; 31. e.Graphics.DrawString(data.ToString(), printFont, Brushes.Black, leftMargin, yPos, new StringFormat()); This block of code sends the contents of the data variable to the printer. The page is printed using the Arial font (you can specify any font and size that is installed on your computer). The margins of the document are determined by using the bounds specified by the PrintPageEventArgs parameter passed to the method. The line that actually sends the data to the printer is the DrawString statement. You can experiment with different values for the parameters. The code shown above outputs a simple page of text. If you are feeling adventurous, you can add a page header and footer, and graphics to the output. 32. Build and run the application. Create a new member. 33. On the File menu, click Print. The Print dialog box appears. Select a printer and then click Print. A message box appears while the data is formatted and printed. 34. When you have finished, close the application. • If you want to continue to the next chapter Keep Visual Studio 2005 running and turn to Chapter 22. • If you want to exit Visual Studio 2005 for now On the File menu, click Exit. If you see a Save dialog box, click Yes. . previews. You can use any of these common dialog boxes in Visual Studio 2005 through the common dialog controls. Using the SaveFileDialog Control In the following. displays the Save File dialog box by using the ShowDialog method. The Save File dialog box is modal, which means that the user cannot continue using any other