
- •brief contents
- •about this book
- •The Windows Forms namespace
- •Part 1: Hello Windows Forms
- •Part 2: Basic Windows Forms
- •Part 3: Advanced Windows Forms
- •Who should read this book?
- •Conventions
- •Action
- •Result
- •Source code downloads
- •Author online
- •acknowledgments
- •about .NET
- •Casting the .NET
- •Windows Forms overview
- •about the cover illustration
- •Hello Windows Forms
- •1.1 Programming in C#
- •1.1.1 Namespaces and classes
- •1.1.2 Constructors and methods
- •1.1.3 C# types
- •1.1.4 The entry point
- •1.1.5 The Application class
- •1.1.6 Program execution
- •1.2 Adding controls
- •1.2.1 Shortcuts and fully qualified names
- •1.2.2 Fields and properties
- •1.2.3 The Controls property
- •1.3 Loading files
- •1.3.1 Events
- •1.3.2 The OpenFileDialog class
- •1.3.3 Bitmap images
- •1.4 Resizing forms
- •1.4.1 Desktop layout properties
- •1.4.2 The Anchor property
- •1.4.3 The Dock property
- •1.5 Recap
- •2.1 Programming with Visual Studio .NET
- •2.1.1 Creating a project
- •Action
- •Result
- •2.1.2 Executing a program
- •Action
- •Result
- •2.1.3 Viewing the source code
- •View the code generated by Visual Studio .NET
- •Action
- •Result
- •2.2 Adding controls
- •2.2.1 The AssemblyInfo file
- •Action
- •Results
- •2.2.2 Renaming a form
- •Action
- •Result
- •2.2.3 The Toolbox window
- •Action
- •Result
- •2.3 Loading files
- •2.3.1 Event handlers in Visual Studio .NET
- •Action
- •Result
- •2.3.2 Exception handling
- •Action
- •Result
- •Action
- •Results and Comments
- •2.4 Resizing forms
- •2.4.1 Assign the Anchor property
- •Action
- •Result
- •2.4.2 Assign the MinimumSize property
- •Action
- •Result
- •2.5 Recap
- •Basic Windows Forms
- •Menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.3 Click events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.5 Context menus
- •Action
- •Result
- •Action
- •Result
- •3.6 Recap
- •Status bars
- •4.1 The Control class
- •4.2 The StatusBar class
- •Action
- •Result
- •Action
- •Result
- •4.3.1 Adding panels to a status bar
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •4.5 Recap
- •Reusable libraries
- •5.1 C# classes and interfaces
- •5.2 Class libraries
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.3 Interfaces revisited
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.4 Robustness issues
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Common file dialogs
- •Action
- •Results
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.3 Paint events
- •Action
- •Result
- •Action
- •Result
- •6.4 Context menus revisited
- •Action
- •Result
- •Action
- •Result
- •6.5 Files and paths
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.6 Save file dialogs
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.7 Open file dialogs
- •Action
- •Result
- •Action
- •Result
- •6.8 Recap
- •Drawing and scrolling
- •7.1 Form class hierarchy
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •7.4 Panels
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Dialog boxes
- •8.1 Message boxes
- •Action
- •Result
- •Action
- •Result
- •8.1.4 Creating A YesNoCancel dialog
- •Action
- •Result
- •Action
- •Result
- •8.2 The Form.Close method
- •8.2.1 The relationship between Close and Dispose
- •Action
- •Result
- •8.3 Modal dialog boxes
- •Action
- •Result
- •Action
- •Result
- •8.3.2 Preserving caption values
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Basic controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.1.2 Creating a derived form
- •Action
- •Result
- •9.2 Labels and text boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.3.6 Adding AlbumEditDlg to our main form
- •Action
- •Result
- •Action
- •Result
- •9.4 Recap
- •List controls
- •10.1 List boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.2 Multiselection list boxes
- •10.2.1 Enabling multiple selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.3 Combo boxes
- •Action
- •Result
- •Action
- •Result
- •10.4 Combo box edits
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.5 Owner-drawn lists
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •More controls
- •Action
- •Result
- •Action
- •Result
- •11.2 Tab pages
- •Action
- •Result
- •Action
- •Result
- •11.3.1 Dates and times
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •11.5 Recap
- •A .NET assortment
- •12.1 Keyboard events
- •Action
- •Result
- •Action
- •Result
- •12.2 Mouse events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.3 Image buttons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.4 Icons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.5 Recap
- •Toolbars and tips
- •13.1 Toolbars
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •13.4.2 Creating tool tips
- •Action
- •Result
- •Action
- •Result
- •Advanced Windows Forms
- •List views
- •14.2 The ListView class
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.2.3 Populating a ListView
- •Action
- •Result
- •Action
- •14.3 ListView columns
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.6 Recap
- •Tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.3 Dynamic tree nodes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.4 Node selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.5 Fun with tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Multiple document interfaces
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.3 Merged menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.4 MDI children
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.5 MDI child window management
- •Action
- •Result
- •Action
- •Result
- •16.6 Recap
- •Data binding
- •17.1 Data grids
- •Action
- •Result
- •Action
- •Result
- •17.2 Data grid customization
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Odds and ends .NET
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.2 Timers
- •Action
- •Result
- •Action
- •Result
- •18.3 Drag and drop
- •Action
- •Result
- •Action
- •Result
- •18.4 ActiveX controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.5 Recap
- •C# primer
- •A.1 C# programs
- •A.1.1 Assemblies
- •A.1.2 Namespaces
- •A.2 Types
- •A.2.1 Classes
- •A.2.2 Structures
- •A.2.3 Interfaces
- •A.2.4 Enumerations
- •A.2.5 Delegates
- •A.3 Language elements
- •A.3.1 Built-in types
- •A.3.2 Operators
- •A.3.3 Keywords
- •A.4 Special features
- •A.4.1 Exceptions
- •A.4.2 Arrays
- •A.4.3 Main
- •A.4.4 Boxing
- •A.4.5 Documentation
- •.NET namespaces
- •B.1 System.Collections
- •B.2 System.ComponentModel
- •B.3 System.Data
- •B.4 System.Drawing
- •B.5 System.Globalization
- •B.6 System.IO
- •B.7 System.Net
- •B.8 System.Reflection
- •B.9 System.Resources
- •B.10 System.Security
- •B.11 System.Threading
- •B.12 System.Web
- •B.13 System.Windows.Forms
- •B.14 System.XML
- •Visual index
- •C.1 Objects
- •C.2 Marshal by reference objects
- •C.3 Components
- •C.4 Common dialogs
- •C.7 Event data
- •C.8 Enumerations
- •For more information
- •bibliography
- •Symbols
- •Index

While this may not be the prettiest image printing application, it does demonstrate some important principles, such as using the page margins and text wrapping. We will present the changes in two parts, one for each of our ParentForm and MainForm objects.
18.1.1USING THE PRINT CLASSES
The parent form will make direct use of the print classes previously mentioned, contain the menu items for printing, and maintain the required PrintDocument object. Placing the print document on the parent form ensures that any changes made to the page margins or other document settings are seen by all child forms in the application.
The following tables detail the changes required on the parent form.
Set the version number for the MyPhotos application to 18.1.
MODIFY PARENT FORM TO SUPPORT PRINT MENUS
|
|
|
|
|
Action |
|
|
|
Result |
||
|
|
|
|
|
|
|
|
|
|
||
1 |
In the ParentForm.cs [Design] window, add |
|
|||||||||
|
three menus and a separator to the File |
|
|||||||||
|
menu. |
|
|
|
|
|
|
|
|
||
|
|
|
|
|
Settings |
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Menu |
|
Property |
|
Value |
|
||||
|
|
separator |
|
MergeOrder |
|
6 |
|
|
|
||
|
|
Page |
|
(Name) |
|
menuPageSetup |
|
||||
|
|
Setup |
|
MergeOrder‘ |
|
7 |
|
|
|
||
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
Text |
|
Page Set&up… |
|
|||
|
|
|
(Name) |
|
menuPrintPreview |
|
|||||
|
|
Preview |
|
MergeOrder |
|
7 |
|
|
|
||
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
Text |
|
Print Pre&view |
|
|||
|
|
|
(Name) |
|
menuPrint |
|
|||||
|
|
|
|
|
MergeOrder |
|
7 |
|
|
|
|
|
|
|
|
|
Shortcut |
|
CtrlP |
|
|||
|
|
|
|
|
Text |
|
&Print… |
|
|||
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
2 |
Also drag a PrintDocument object onto the |
|
|||||||||
|
form. |
|
|
|
|
|
|
|
|
||
|
|
|
|
|
Settings |
|
|||||
|
|
|
|
|
|
|
|||||
|
|
|
Property |
|
|
Value |
|
||||
|
|
|
|
(Name) |
|
printDoc |
|
||||
|
|
|
DocumentName |
Image Document |
|
||||||
|
The object appears in the component tray of |
|
|||||||||
|
the designer window. |
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
PRINTING |
605 |

These menus provides the necessary user interface support. Next we hook up our three print menus in the ParentForm class.
HANDLE PRINT RELATED MENUS IN PARENT FORM
|
Action |
Result |
|
|
|
3 |
Add a Click event handler for the |
private void menuPageSetup_Click |
|
Page Setup menu to display a |
(object sender, System.EventArgs e) |
|
PageSetupDialog window for the |
{ |
|
PageSetupDialog dlg |
|
|
form’s print document. |
|
|
= new PageSetupDialog(); |
|
|
|
dlg.Document = printDoc; |
|
|
dlg.ShowDialog(); |
|
|
} |
|
|
|
4 |
Add a Click event handler for the |
private void menuPrintPreview_Click |
|
Print Preview menu to display a |
(object sender, System.EventArgs e) |
|
PrintPreviewDialog window for |
{ |
|
PrintPreviewDialog dlg |
|
|
the form’s print document. |
|
|
= new PrintPreviewDialog(); |
|
|
Note: The PrintPreviewDialog |
dlg.Document = printDoc; |
|
dlg.ShowDialog(); |
|
|
window displays the document to |
|
|
} |
|
|
be printed within a PrintPreview- |
|
|
Control object contained within |
|
|
the preview window. |
|
|
|
|
5 |
Add a Click event handler for the |
private void menuPrint_Click |
|
Print menu to display a PrintDialog |
(object sender, System.EventArgs e) |
|
window for the form’s print |
{ |
|
PrintDialog dlg = new PrintDialog(); |
|
|
document. |
|
|
dlg.Document = printDoc; |
|
|
Note: The common print dialog |
if (dlg.ShowDialog() == DialogResult.OK) |
|
{ |
|
|
allows the user to select standard |
|
|
printDoc.Print(); |
|
|
settings such as which printer to use |
} |
|
and the number of copies to make. |
} |
|
If the user clicks the OK button, then |
|
|
we invoke the Print method in the |
|
|
PrintDocument class to initiate the |
|
|
actual print operation. |
|
|
|
|
6 |
Handle the PrintPage event for the |
private void printDoc_PrintPage |
|
PrintDocument object on the parent |
(object sender, System.Drawing. |
|
form. |
Printing.PrintPageEventArgs e) |
|
{ |
|
|
|
|
|
Note: This event occurs for each |
|
|
page to be printed. The BeginPrint |
|
|
and EndPrint events occur at the |
|
|
start and end of the entire print |
|
|
operation, respectively. |
|
|
|
|
7 |
In this handler: |
MainForm f = ActiveMdiChild as MainForm; |
|
a. If the active child is a MainForm |
if (f != null) |
|
f.PrintCurrentImage(e); |
|
|
object, call the yet-to-be-written |
else |
|
PrintCurrentImage method on |
e.Cancel = true; |
|
this object. |
} |
|
|
|
|
b. Otherwise, cancel the print |
|
|
operation. |
|
|
|
|
606 |
CHAPTER 18 ODDS AND ENDS .NET |

These event handlers establish the required printing support for the parent form. The printing logic for the child form is presented next.
18.1.2DRAWING A PRINT PAGE
With our user interface logic in place, we are ready to implement the printing of a page. This is done using the PrintPageEventArgs parameter provided to the PrintPage event handler. This class is summarized in .NET Table 18.1.
.NET Table 18.1 PrintPageEventArgs class
The PrintPageEventArgs class represents an event argument containing information required for printing pages to a printer. This class is part of the System.Drawing.Printing namespace, and inherits from the System.EventArgs class.
|
Cancel |
Gets or sets whether the print job should be |
|
|
cancelled. |
|
Graphics |
Gets the Graphics object on which to paint the |
|
|
page to print. |
|
HasMorePages |
Gets or sets whether an additional page should |
|
|
be printed after the current one. |
Public Properties |
|
|
|
MarginBounds |
Gets the printable area of a page, which is the |
|
|
rectangle within the margins of the page. |
|
PageBounds |
Gets the page area, which is the rectangle |
|
|
representing the entire page. |
|
PageSettings |
Gets the PageSettings object representing the |
|
|
settings for the current page. |
|
|
|
We will implement a PrintCurrentImage method in the MainForm class to make use of this parameter. Internally, this will draw the photograph using the provided Graphics object, and use an internal PrintTextString method to draw the individual properties for the photograph.
IMPLEMENT THE PRINTCURRENTIMAGE METHOD
|
Action |
Result |
|
|
|
1 |
In the MainForm.cs code |
using System.Drawing.Printing; |
|
window, indicate that we will |
|
|
use members of the |
|
|
System.Drawing.Printing |
|
|
namespace. |
|
|
|
|
2 |
Add a PrintCurrentImage |
public void PrintCurrentImage |
|
method that accepts a |
(PrintPageEventArgs e) |
|
PrintPageEventArgs object as |
{ |
|
|
|
|
a parameter. |
|
|
|
|
PRINTING |
607 |

IMPLEMENT THE PRINTCURRENTIMAGE METHOD (continued)
|
Action |
Result |
|
|
|
3 |
If there is no current photo, then |
Photograph photo = _album.CurrentPhoto; |
|
abort the print operation. |
if (photo == null) |
|
|
{ |
|
|
// nothing to print, so abort |
|
|
e.Cancel = true; |
|
|
return; |
|
|
} |
|
|
|
4 |
Otherwise, create some |
// Establish some useful shortcuts |
|
shortcuts for the margins of the |
float leftMargin = e.MarginBounds.Left; |
|
page and the Graphics object. |
float rightMargin = e.MarginBounds.Right; |
|
float topMargin = e.MarginBounds.Top; |
|
|
|
|
|
|
float bottomMargin |
|
|
= e.MarginBounds.Bottom; |
|
|
float printableWidth = e.MarginBounds.Width; |
|
|
float printableHeight |
|
|
= e.MarginBounds.Height; |
|
|
Graphics g = e.Graphics; |
|
|
|
5 |
Create a Font object: |
Font printFont |
|
a. Use 11 point Times New |
= new Font("Times New Roman", 11); |
|
float fontHeight = printFont.GetHeight(g); |
|
|
Roman. |
float spaceWidth = g.MeasureString(" ", |
|
b. Use the GetHeight method |
printFont).Width; |
|
|
|
|
to determine the height of |
|
|
each line of text. |
|
|
c. Use the MeasureString |
|
|
method to determine the size |
|
|
of a space. |
|
|
|
|
6 |
Determine the correct length so |
// Draw image in box 75% of shortest side |
|
that the image can be drawn |
float imageBoxLength; |
|
into a box which is 75% of the |
float xPos = leftMargin; |
|
float yPos = topMargin + fontHeight; |
|
|
shortest side of the page. |
|
|
if (printableWidth < printableHeight) |
|
|
Note: This logic accounts for |
{ |
|
imageBoxLength = printableWidth * 75/100; |
|
|
both landscape and portrait |
|
|
yPos += imageBoxLength; |
|
|
page orientation. The xPos and |
} |
|
yPos variables represent where |
else |
|
the first line of text should be |
{ |
|
imageBoxLength = printableHeight * 75/100; |
|
|
drawn. |
|
|
xPos += imageBoxLength + spaceWidth; |
|
|
|
} |
|
|
|
7 |
Draw the image into a box of the |
// Draw image at start of the page |
|
determined size. |
Rectangle imageBox |
|
|
= new Rectangle((int)leftMargin + 1, |
|
|
(int)topMargin + 1, |
|
|
(int)imageBoxLength, |
|
|
(int)imageBoxLength); |
|
|
g.DrawImage(photo.Image, |
|
|
photo.ScaleToFit(imageBox)); |
|
|
|
8 |
Determine the RectangleF |
// Determine rectangle for text |
|
object where all text should be |
RectangleF printArea |
|
drawn. |
= new RectangleF(xPos, yPos, |
|
rightMargin - xPos, |
|
|
|
|
|
|
bottomMargin - yPos); |
|
|
|
608 |
CHAPTER 18 ODDS AND ENDS .NET |