Sie sind auf Seite 1von 82

Practical .

NET Series Web/C#/Graphics


Copyright 2007 Mindcracker LLC and Microgold Software Inc. 1

Printing in C# Made Easy






Platform Support: .NET 2.0, 1.1, 1.0
Language: C#







Authors:
C# Corner Authors Team
Published on: May 15, 2007














@2007 Mindcracker LLC. All rights reserved. United States and International copyright
laws protect this property. Mindcracker LLC or the author of this material has no
affiliation with Microsoft or any other companies that develops the software. Some
keywords used in this material are registered trademarks of their respective owners.

Reproduction or printing multiple copies of this material is prohibited. If you need
multiple copies of this material, please contract authors@c-sharpcorner.com.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 2

Printing Introduction

This article covers the following topics -

Basic understanding of printing process in .NET
How to get and set printer and page settings
How to get and set paper size
How to get and set paper tray
How to print text and text files
How to print drawings and graphic shapes
How to print images
How to use print dialogs
How to write your own custom printing and page setup dialogs
How to print multi page documents
How to print a Form and its controls
How to print invoices
How to print a ruler
How to print a bar code
How to print a DataGridView control

Understanding the Printing Process

The following steps are required in a printing process.

Step 1: Specify a printer

First step to specify what printer you are going to use for printing. In code, we create a
Pr i nt Document object and specify the printer by setting its PrinterName property.

Step 2: Set the printer and page properties.

This is an optional step. This step includes setting printer and page settings. If we dont
set these properties, the default settings of the printer will be used.

Step 3: Set the print-page event handler.

The print-page event handler is responsible for printing. We create a print-page event
handler by setting the Pr i nt Document . Pr i nt Page member.

Step 4: Print the document.
Finally, we call the Pr i nt Document . Pr i nt method, which sends printing objects to
the printer.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 3

NOTE

All printing related functionality in .NET Framework is definted in the
System.Drawing.Printing namespace. Before you use any printing related classes or
objects, you must import the System.Drawing.Printing namespace using the following
code:

usi ng Syst em. Dr awi ng. Pr i nt i ng;

NOTE

Before you use any printer-related classes in your application, a printer must be installed
on your machine.

Hello, Printer!

Now, lets create our first printing application. In this application, we will print a text,
Hello, Printer! to the printer from our application.

Create a Windows Forms application using Visual Studio and import the
System.Drawing.Printing namespace using the following code:

usi ng Syst em. Dr awi ng. Pr i nt i ng;

Now, we add a label, a combo box, and a button controls to the form and change their
names and text accordingly. We change combo boxs Name property to to PrintersList
and buttons Name property to PrintButton. The final form should look like Figure 1.



Figure 1: Hello, Printer! Application

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 4

On lets load all installed printers in the PrintersList combo box by adding Listing 1 code
on the Forms Load event handler.

Listing 1: Getting all installed printers

pr i vat e voi d For m1_Load( obj ect sender , Event Ar gs e)
{
f or each ( St r i ng pr i nt er i n Pr i nt er Set t i ngs. I nst al l edPr i nt er s)
{
pr i nt er sLi st . I t ems. Add( pr i nt er . ToSt r i ng( ) ) ;
}
}

The Pr i nt er Set t i ng. I nst al l edPr i nt er in Listing 1 returns the installed
printers on a machine.

Now, lets add code to the Print button click event handler by double clicking on the Print
bytton. See Listing 2.

In Listing 2, we create a Pr i nt Document object and set the
Pr i nt Document . Pr i nt er Set t i ngs. Pr i nt er Name property to the printer
selected from the printer list combo box. Then we add print-page event handler and call
the Pr i nt Document . Pr i nt method, which actually prints the document.

Listing 2: The Print button click event handler

pr i vat e voi d Pr i nt But t on_Cl i ck( obj ect sender , Event Ar gs e)
{
/ / Cr eat e a Pr i nt Document obj ect
Pr i nt Document Pr i nt Doc = new Pr i nt Document ( ) ;
/ / Set Pr i nt er Name as t he sel ect ed pr i nt er i n t he pr i nt er s l i st
Pr i nt Doc. Pr i nt er Set t i ngs. Pr i nt er Name =
Pr i nt er sLi st . Sel ect edI t em. ToSt r i ng( ) ;
/ / Add Pr i nt Page event handl er
Pr i nt Doc. Pr i nt Page += new Pr i nt PageEvent Handl er ( Pr i nt PageMet hod) ;
/ / Pr i nt t he document
Pr i nt Doc. Pr i nt ( ) ;
}

The last step is to add the print-page event handler code. See code Listing 3. This code is
responsible for creating a Gr aphi cs object for the printer. It calls the Dr awSt r i ng
method, which is responsible for drawing text. First we create a Gr aphi cs object from
Pr i nt PageEvent Ar gs. Gr aphi cs. Then we create Font and Sol i dBr ush
objects and call Dr awSt r i ng to draw some text on the printer. The Dr awSt r i ng
method takes a string that represents the text to be drawn; the font; a brush; and a layout
rectangle that represents the starting point, width, and height of a rectangle for the text.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 5

Listing 3: The print-page event handler

publ i c voi d Pr i nt PageMet hod( obj ect sender , Pr i nt PageEvent Ar gs ppev)
{
/ / Get t he Gr aphi cs obj ect
Gr aphi cs g = ppev. Gr aphi cs;
/ / Cr eat e a f ont ver dana wi t h si ze 14
Font f ont = new Font ( " Ver dana" , 20) ;
/ / Cr eat e a sol i d br ush wi t h r ed col or
Sol i dBr ush br ush = new Sol i dBr ush( Col or . Red) ;
/ / Cr eat e a r ect angl e
Rect angl e r ect = new Rect angl e( 50, 50, 200, 200) ;
/ / Dr aw t ext
g. Dr awSt r i ng( " Hel l o, Pr i nt er ! " , f ont , br ush, r ect ) ;
}

Now, build and run the application, select a printer from the printers list, and click the
Print button. You should see Hello, Printer! on you printed page on the printer.

Working with Printer and Page Properties

There are times when you need to control printer and page settings programmatically
such as number of copies, paper size, paper kind and print quality. All this may be
controlled through the PrinterSettings property of PrintDocument and PageSettings
classes, which is represented by the PrinterSettings class.

Lets take a quick look at the PrinterSettings class and its members. After that, we will
write an application that allows us to get and set printer and page settings
programmatically.

The I nst al l edPr i nt er s static property returns the names of all available printers
on a machine, including printers available on the network. The following code snippet
iterates through all the available printers on a machine.

f or each ( St r i ng pr i nt er i n
Pr i nt er Set t i ngs. I nst al l edPr i nt er s)
{
st r i ng st r = pr i nt er . ToSt r i ng( ) ;
}

The Paper Si zes property returns the paper sizes supported by a printer. It returns all
the paper sizes in a Pr i nt er Set t ngs. Paper Si zeCol l ect i on object. The
following code snippet iterates through all the available paper sizes.

Pr i nt er Set t i ngs pr s = new Pr i nt er Set t i ngs( ) ;
f or each ( Paper Si ze ps i n pr s. Paper Si zes)
{
st r i ng st r = ps. ToSt r i ng( ) ;
}

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 6

The Pr i nt er Resol ut i ons property returns all the resolutions supported by a printer.
It returns all the printer resolutions in a
Pr i nt er Set t i ngs. Pr i nt er Resol ut i onsCol l ect i on object that contains
Pr i nt er Resol ut i on object. The following code snippet reads the printer resolution
and adds them to a Li st Box control. Here Your Pr i nt er Name is the name of the
printer you want to use. If you do not set a printer name, the default printer will be used.

Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
/ / Set t he pr i nt er name
ps. Pr i nt er Name = Your Pr i nt er Name;
f or each ( Pr i nt er Resol ut i on pr i n ps. Pr i nt er Resol ut i ons)
{
st r i ng st r = pr . ToSt r i ng( ) ;
}

The Pr i nt er Resol ut i on class, which represents the resolution of a printer, is used
by the Pr i nt er Resol ut i ons and Pr i nt er Resol ut i on properties of
Pr i nt er Set t i ngs to get and set printer resolutions. Using these two properties, we
can get all the printer resolutions available on a printer. We can also use it to set the
printing resolution for a page.

The Pr i nt er Resol ut i on class has three properties: Ki nd, X, and Y. The Ki nd
property is used to determine whether the printer resolution is the
Pr i nt er Resol ut i onKi nd enumeration type or Cust om. If its Cust om, the X and
Y properties are used to determine the printer resolution in the horizontal and vertical
directions, respectively in dots per inch. If the Ki nd property is not Cust om, the value
of X and Y each is 1.

The CanDupl ex property is used to determine whether a printer can print on both sides
of a page. If so, we can set the Dupl ex property to t r ue to print on both sides of page.
The following code snippet determines whether your printer can print on both sides of a
page.

Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
st r i ng st r = ps. CanDupl ex. ToSt r i ng( ) ;

The Dupl ex enumeration specifies the printers duplex settings, which are used by
Pr i nt er Set t i ngs. The members of the Dupl ex enumeration are described in
Table 1.

The Col l at e property (both get and set) is used only if we choose to print more than
one copy of a document. If the value of Col l at e is t r ue, and entire copy of the
document will be printed before the next copy is printed. If the value is f al se, all copies
of page 1 will be printed, then all copies of page 2, and so on. The following code
snipped sets the Col l at e property of Pr i nt er Set t i ngs to t r ue:

Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
ps. Col l at e = t r ue;
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 7


The Copi es property (both get and set) allows us to enter the number of copies of a
document that we want to print. Not all printers support this feature (in which case this
setting will be ignored).

The I sPl ot t er property tells us if the printer were using is actually a plotter that can
accept plotter commands. The following code snipped indicates whether the printer is a
plotter:

Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
st r i ng st r = ps. I sPl ot t er . ToSt r i ng( ) ;

If we print without setting the Pr i nt er Name property, our printout will be sent to the
default printer. The Pr i nt er Name property allows us to specify a printer to use. The
I sVal i d property tells us whether the Pr i nt er Name value we have selected
represents a valid printer on our system. The following code snippets checks if a printer is
a vaid printer or not.

Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
st r i ng st r = ps. I sVal i d. ToSt r i ng( ) ;

The Maxi mumCopi es property determines how many copies the printer can print.
Some printers do not allow us to print more than one copy at a time. The following code
snippet reads the maximum number of copies that a printer can print.

Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
i nt maxcopi es = ps. Maxi mumCopi es;

The Suppor t sCol or property tells us whether the current printer supports printing in
color. It will return t r ue if the printer supports color printing and f al se otherwise.
The following code snippet reads the value of the Suppor t sCol or s property to find
out whether a printer supports colors.

Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
st r i ng st r = ps. Suppor t sCol or . ToSt r i ng( ) ;

Getting and Setting Printer Paper Size

The Paper Si ze class represents the size of paper used in printing. This class is used by
Pr i nt er Set t i ngs through its Paper Si zes property to get and set the paper sizes
for the printer.

The Paper Si ze class has four properties: Hei ght , Wi dt h, Ki nd, and
Paper Name. The Hei ght and Wi dt h properties are used to get and set the papers
height and width, respectively, in hundredths of an inch. The Paper Name property is
used to get and set the name of the type of paper, but it can be used only when the Ki nd
property is set to Cust om. The Ki nd property returns the type of paper.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 8

The code in Listing 4 reads the Paper Si ze properties.

Listing 4: Reading PaperSize properties

Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
Consol e. Wr i t eLi ne( " Paper Si zes" ) ;
f or each ( Paper Si ze psi ze i n ps. Paper Si zes)
{
st r i ng st r 1 = psi ze. Ki nd. ToSt r i ng( ) ;
st r i ng st r 2 = psi ze. Paper Name. ToSt r i ng( ) ;
st r i ng st r 3 = psi ze. Hei ght . ToSt r i ng( ) ;
st r i ng st r 4 = psi ze. Wi dt h. ToSt r i ng( ) ;
}

Getting and Setting Paper Tray

The Paper Sour ce class specifies the paper tray from which the printer retrieves the
paper for the current printing task. This class is used by Pr i t ner Set t i ngs through its
Paper Sor uces property to get and set the paper source trays that a re available on the
printer. The Paper Si ze class has two properties: Ki nd and Sour ceName. The
Ki nd property returns an enumerated value for the paper source, and Sor uceName
returns the name of the paper source as a string.

The code Listing 5 reads all the paper sources and displays them in a message box.

Listing 5: Reading paper sources

Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
f or each ( Paper Sour ce p i n ps. Paper Sour ces)
{
MessageBox. Show( p. Sour ceName) ;
}

Printer and Page Properties Application

The basis of the preceding discussion of printer settings, and of printer related classes and
their members, lets write an application using these classes. In this application we will
display available printers, the resolutions they support, available paper sizes, and other
printer properties. This application will also allow us to set printer properties.

First we create a Windows application and add a combo box, two list boxes, three
buttons, six check boxes, and two text boxes to the form. The final form looks like
Figure 8. Then we add a reference to the Syst em. Dr awi ng. Pr i nt i ng namespace.

Next we write code. The Available Printers combo box displays all available installed
printers on the machine in the Li st Box control. We load all installed printers on the
forms load event. As Listing 6 shows, we use the I nsal l edPr i nt er s static property
of Pr i nt er Set t i ngs, which returns all installed printer names. We check if the
installed printers count is more than 0 and add the installed printers to the combo box.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 9


Listing 6: Reading all available printers

pr i vat e voi d For m1_Load ( obj ect sender , Syst em. Event Ar gs e)
{
/ / See i f any pr i nt er s ar e i nst al l ed
i f ( Pr i nt er Set t i ngs. I nst al l edPr i nt er s. Count <= 0)
{
MessageBox. Show( " Pr i nt er not f ound" ) ;
r et ur n;
}
/ / Get al l t he avai l abl e pr i nt er s and add t hemt o t he combo box
f or each ( St r i ng pr i nt er i n Pr i nt er Set t i ngs. I nst al l edPr i nt er s)
{
Pr i nt er sLi st . I t ems. Add( pr i nt er . ToSt r i ng( ) ) ;
}
}



Figure 2: The printer settings form

The Get Printer Resolution button returns resolutions supported by a printer selected in
Li st Box1. The Pr i nt er Resol ut i ons property of Pr i nt er Set t i ngs returns
the printer resolutions supported by the printer Listing 7 reads all available resolutions for
the selected printer in Li st Box1 and adds them to Li st Box2.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 10

Listing 7: Reading printer resolutions

pr i vat e voi d but t on2_Cl i ck( obj ect sender , Syst em. Event Ar gs e)
{
/ / I f no pr i nt er i s sel ect ed
i f ( Pr i nt er sLi st . Text == st r i ng. Empt y)
{
MessageBox. Show( " Sel ect a pr i nt er f r omt he l i st " ) ;
r et ur n;
}
/ / Get t he cur r ent sel ect ed pr i nt er f or mt he l i st of pr i nt er s
st r i ng st r = Pr i nt er sLi st . Sel ect edI t em. ToSt r i ng( ) ;
/ / Cr eat e a Pr i nt er Set t i ngs obj ect s
Pr i nt er Set t i ngs Pr Set t i ng = new Pr i nt er Set t i ngs( ) ;
/ / Set t he cur r ent pr i nt er
Pr Set t i ng. Pr i nt er Name = st r ;
/ / Read al l pr i nt er r esol ut i ons and add t hemt o t he l i st box
f or each ( Pr i nt er Resol ut i on pr
i n Pr Set t i ng. Pr i nt er Resol ut i ons)
{
Resol ut i onLi st . I t ems. Add( pr . ToSt r i ng( ) ) ;
}
}

The Get Paper Size button returns the available paper sizes. Again we use the
Paper Si zes property of Pr i nt er Set t i ngs, which returns all available paper sizes.
Listing 8 reads all available paper sizes and adds them to the list box.

Listing 8: Reading paper sizes

pr i vat e voi d but t on3_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / I f no pr i nt er i s sel ect ed
i f ( Pr i nt er sLi st . Text == st r i ng. Empt y)
{
MessageBox. Show( " Sel ect a pr i nt er f r omt he l i st " ) ;
r et ur n;
}
/ / Cr eat e a pr i nt er set t i ngs
Pr i nt er Set t i ngs pr s = new Pr i nt er Set t i ngs( ) ;
/ / Get t he cur r ent sel ect ed pr i nt er f r omt he l i st of pr i nt er s
st r i ng st r = Pr i nt er sLi st . Sel ect edI t em. ToSt r i ng( ) ;
pr s. Pr i nt er Name = st r ;
/ / Read paper si zes and add t hemt o t he l i st box
f or each ( Paper Si ze Pr Set t i ng i n pr s. Paper Si zes)
{
l i st Box1. I t ems. Add( Pr Set t i ng. ToSt r i ng( ) ) ;

}
}

The Get Printer Properties buttons gets the printer properties and sets the check boxes
and text box controls according to the values returned. The Get Printer Properties
button click event handler code is given in Listing 9. We read many printer properties
that were discussed earlier in this article.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 11

Listing 9: Reading printer properties

pr i vat e voi d Get Pr oper t i es_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / I f no pr i nt er i s sel ect ed
/ / I f no pr i nt er i s sel ect ed
i f ( Pr i nt er sLi st . Text == st r i ng. Empt y)
{
MessageBox. Show( " Sel ect a pr i nt er f r omt he l i st " ) ;
r et ur n;
}
Pr i nt er Set t i ngs Pr Set t i ng = new Pr i nt er Set t i ngs( ) ;
st r i ng st r = Pr i nt er sLi st . Sel ect edI t em. ToSt r i ng( ) ;
Pr Set t i ng. Pr i nt er Name = st r ;
/ / Check i f t he pr i nt er i s val i d
i f ( ! Pr Set t i ng. I sVal i d)
{
MessageBox. Show( " Not a val i d pr i nt er " ) ;
r et ur n;
}
/ / Set pr i nt er name and copi es
t ext Box1. Text = Pr Set t i ng. Pr i nt er Name. ToSt r i ng( ) ;
t ext Box2. Text = Pr Set t i ng. Copi es. ToSt r i ng( ) ;
/ / I f pr i nt er i s t he def aul t pr i nt er
i f ( Pr Set t i ng. I sDef aul t Pr i nt er == t r ue)
I sDef Pr i nt er ChkBox. Checked = t r ue;
el se
I sDef Pr i nt er ChkBox. Checked = f al se;
/ / I f pr i nt er i s a pl ot t er
i f ( Pr Set t i ng. I sPl ot t er )
I sPl ot t er ChkBox. Checked = t r ue;
el se
I sPl ot t er ChkBox. Checked = f al se;
/ / Dupl ex pr i nt i ng possi bl e?
i f ( Pr Set t i ng. CanDupl ex)
CanDupl exChkBox. Checked = t r ue;
el se
CanDupl exChkBox. Checked = f al se;
/ / Col l at e?

i f ( Pr Set t i ng. Col l at e)
Col l at eChkBox. Checked = t r ue;
el se
Col l at eChkBox. Checked = f al se;
/ / Pr i nt er val i d?
i f ( Pr Set t i ng. I sVal i d)
I sVal i dChkBox. Checked = t r ue;
el se
I sVal i dChkBox. Checked = f al se;
/ / Col or pr i nt er ?
i f ( Pr Set t i ng. Suppor t sCol or )
SuppCol or sChkBox. Checked = t r ue;
el se
SuppCol or sChkBox. Checked = f al se;
}
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 12

Now lets run the application. By default, the Available Printers combo box displays all
available printers. Select a printer from the list, and click the Get Printer Resolution
button, which display the printer resolutions supported by the selected printer. Also click
on the Get Paper Size and Get Printer Properties buttons. The final output of the
application is shown in Figure 3.

We will be using many Pr i nt er Set t i ngs class members throughout this article.

Understanding PrintDocument and Print Events

So far we have seen how to print simple text and how to read and set printer settings. In
the previous sections we saw that in a printing application, we create a
Pr i nt Document object, set its printer name, set the printer page event handler, and
then call the Pr i nt method. Pr i nt Document offers more than this. In this section we
will cover Pr i nt Document members and print events.

The Pr i nt Document class is used to tell the printing system how printing will take
place. Table 1 describes the properties of the Pr i nt Document class.

Besides the properties described in Table 1, Pr i nt Document also provides printing-
related methods that invoke print events. These methods are described in Table 2.



Figure 3: Reading printer properties

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 13

Table 1: PrintDocument properties

Property Description
Def aul t PageSet t i ngs
Represents the page settings using a PageSet t i ngs
object.
Document Name Returns the name of the document to be displayed in a
print status dialog box or printer queue while printing the
document.
Pr i nt Cont r ol l er Returns the print controller that guides the printing
process.
Pr i nt er Set t i ngs Returns the printer settings represented by a
Pr i nt er Set t i ngs object.


Table 2: PrintDocument methods

Method Description
OnBegi nPr i nt
Raise the Begi nPr i nt event, which is called after the
Pr i nt method and before the first page of the document
is printed.
OnEndPr i nt
Raises the EndPr i nt event, which is called when the
last page of the document has been printed.
OnPr i nt Page
Raises the Pr i nt Page event, which is called before a
page prints.
OnQuer yPageSet t i ngs
Raises the Quer yPageSet t i ngs event, which is
called immediately before each Pr i nt Page event.
Pr i nt Starts the documents printing process.


All of these methods allow derived classes to handle the event without attaching a
delegate. This is the preferred technique for handling the event in a derived class. We will
discuss these methods and their events, and how to handle them, in our examples.

Understanding Print Events

During the printing process, the printing system fires events according to the stage of a
printing process. The three common events are Begi nPr i nt , Pr i nt Page, and
EndPr i nt . As their names indicate, the Begi nPr i nt event occurs when the Pr i nt
method is called, and the EndPr i nt event occurs when the last page of the document
has been printed. The Pr i nt Page event occurs for each page being printed (as in
Figure 4) when the Pr i nt method is called and after the Begi nPr i nt event has
occurred.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 14

Figure 4 shows a flowchart for the print events during a printing process. The
Begi nPr i nt event is raised after the Pr i nt method is called. Then the printing
process checks if there are any pages. If there are, the Pr i nt Page event occurs, which
is responsible for the actual printing, and the control goes back to check if there are more
pages to print. When all pages are done printing, the EndPage event is fired.



Figure 4: Print events

The Pr i nt Event Ar gs class provides data for Begi nPr i nt and EndPr i nt events.
This class is inherited from Cancel Event Ar gs, which implements a single property
called Cancel , that indicates if an event should be canceled (in the current .NET
Framework release, Pr i nt Event Ar gs is reserved for future use).

The Begi nPr i nt event occurs when the Pr i nt method is called and before the first
page prints. Begi nPr i nt takes a Pr i nt Event Ar gs object as an argument. This
event is the best place to initialize resources. The Pr i nt Event Handl er method,
which is used to handle the event code, is called whenever the Begi nPr i nt event
occurs.

The Pr i nt Page event occurs when the Pr i nt method is called and before a page
prints. When we create a Pr i nt PageEvent Handl er delegate, we identify a method
that handles the Pr i nt Page event. The event handler is called whenever the
Pr i nt Page event occurs.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 15

The code snipped that follows creates a Pr i nt PageEvent Handl er delegate, where
pd_Pr i nt Page is an event handler:

Pr i nt Document pd = new Pr i nt Document ( ) ;
pd. Pr i nt Page +=
new Pr i nt PageEvent Handl er ( pd_Pr i nt Page) ;

Pr i nt PageEvent Handl er takes a Pr i nt PageEvent Ar gs object as its second
argument, which has the six properties described in Table 3.

The following code snippet shows how to get the Gr aphi cs object from
Pr i nt PageEvent Ar gs:

publ i c voi d pd_Pr i nt Page ( obj ect sender , Pr i nt PageEvent Ar gs ev)
{
/ / Get t he Gr aphi cs obj ect at t ached t o Pr i nt PageEvent Ar gs
Gr aphi cs g = ev. Gr aphi cs;
/ / Use g now
}

The EndPr i nt event occurs when the last page of the document has been printed. It
takes a Pr i nt Event Ar gs object as an argument. This is the best place to free your
resources. The Pr i nt Event Handl er method is called whenever the EndPr i nt
event occurs and is used to handle the event code.

Now lets write an application that shows how to use these events. We create a Windows
application and add a combo box and a button to the form. We set ComboBox. Name to
pr i nt er sLi st and the text to the button to PrintEvent Start. The final form looks
like Figure 5.

Table 3: PrintPageEventArgs properties

Property Description
Cancel Indicates whether the print jobs should be canceled. Both get and
set.
Gr aphi cs
Returns the Gr aphi cs object.
HasMor ePages Indicates whether an additional page should be printed. Used in
multipage document before the Pr i nt methods is called. Both get
and set.
Mar gi nBounds Returns the portion of the page inside the margins.
PageBounds Returns the total area of the page
PageSet t i ngs Returns page setting for the current page.


Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 16



Figure 5: The print events application

Next we add a reference to the Syst em. Dr awi ng. Pr i nt i ng namespace as follows:

usi ng Syst em. Dr awi ng. Pr i nt i ng;

Then we add code on the forms load event handler that adds all installed printers to the
combo box (see Listing 10).

Listing 10: Loading all installed printers

pr i vat e voi d For m1_Load ( obj ect sender , Syst em. Event Ar gs e)
{
/ / See i f any pr i nt er s ar e i nst al l ed
i f ( Pr i nt er Set t i ngs. I nst al l edPr i nt er s. Count <= 0)
{
MessageBox. Show( " Pr i nt er not f ound! " ) ;
r et ur n;
}
/ / Get al l avai l abl e pr i nt er s and add t hemt o t he combo box
f or each ( St r i ng pr i nt er i n Pr i nt er Set t i ngs. I nst al l edPr i nt er s)
{
pr i nt er sLi st . I t ems. Add( pr i nt er . ToSt r i ng( ) ) ;
}
}

Now we write code for the button click event handler. Listing 11 create all three print
event handlers, attaches them to a Pr i nt Document object, and calls
Pr i nt Document s print methods.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 17

Listing 11: Attaching BeginPrint, EndPrint, and PagePrinteventhandlers

pr i vat e voi d Pr i nt Event s_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Get t he sel ect ed pr i nt er
st r i ng pr i nt er Name = pr i nt er sLi st . Sel ect edI t em. ToSt r i ng( ) ;
/ / Cr eat e a Pr i nt Document obj ect and set t he cur r ent pr i nt er
Pr i nt Document pr i nt Dc= new Pr i nt Document ( ) ;
pr i nt Dc. Pr i nt er Set t i ngs. Pr i nt er Name = pr i nt er Name;
/ / Begi nPr i nt event
pr i nt Dc. Begi nPr i nt += new Pr i nt Event Handl er ( BgnPr nt Event Handl er ) ;
/ / Pr i nt Page event
pr i nt Dc. Pr i nt Page += new Pr i nt PageEvent Handl er ( Pr nt PgEvent Handl er ) ;
/ / EndPr i nt event
pr i nt Dc. EndPr i nt +=new Pr i nt Event Handl er ( EndPr nt Event Handl er ) ;
/ / Pr i nt t he document
pr i nt Dc. Pr i nt ( ) ;
}

As state earlier, the Begi nPr i nt event handler can be used to initialize resources
before printing starts, and the EndPr i nt event handler can be used to free allocated
resources. Listing 12 shows all three print event handlers. The Pr i nt Page event
handler uses the properties for Pr i nt PageEvent Ar gs can calls Dr awRect angl e
and Fi l l Rect angl e to print the rectangles. This example simply shows how to call
these events. You can use the Pr i nt Page event handler to draw anything you want to
print, as we have seen in previous examples.

Listing 12: The BeginPrint, EndPrint, and PagePrint event handlers

publ i c voi d BgnPr nt Event Handl er ( obj ect sender , Pr i nt Event Ar gs peaAr gs)
{
/ / Cr eat e a br ush and a pen
r edBr ush = new Sol i dBr ush ( Col or . Red) ;
bl uePen = new Pen ( Col or . Bl ue, 3) ;
}
publ i c voi d EndPr nt Event Handl er ( obj ect sender , Pr i nt Event Ar gs peaAr gs)
{
/ / Rel ease br ush and pen obj ect s
r edBr ush. Di spose( ) ;
bl uePen. Di spose( ) ;
}

publ i c voi d Pr nt PgEvent Handl er ( obj ect snder , Pr i nt PageEvent Ar gs
ppeAr gs)
{
/ / Cr eat e Pr i nt er Set t i ngs obj ect
Pr i nt er Set t i ngs ps = new Pr i nt er Set t i ngs( ) ;
/ / Get Gr aphi cs obj ect
Gr aphi cs g = ppeAr gs. Gr aphi cs;
/ / Cr eat e PageSet t i ngs obj ect
PageSet t i ngs pgSet t i ng = new PageSet t i ngs( ps) ;
/ / Set page mar gi ns
ppeAr gs. PageSet t i ngs. Mar gi ns. Lef t = 50;
ppeAr gs. PageSet t i ngs. Mar gi ns. Ri ght = 100;
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 18

ppeAr gs. PageSet t i ngs. Mar gi ns. Top = 50;
ppeAr gs. PageSet t i ngs. Mar gi ns. Bot t om= 100;
/ / Cr eat e t wo r ect angl es0
Rect angl e r ect 1 = new Rect angl e( 20, 20, 50, 50) ;
Rect angl e r ect 2 = new Rect angl e( 100, 100, 50, 100) ;
/ / Dr aw and f i l l r ect angl es
g. Dr awRect angl e( bl uePen, r ect 1) ;
g. Fi l l Rect angl e ( r edBr ush, r ect 2) ;
}

As this discussion has shown, the print event can be handy when you need to initialize or
free resources.

Printing Text and Text Files

Now lets see how to print text and text files.

Step 1: Create a Windows Forms application
Step 2: Add a reference to the Syst em. Dr awi ng. Pr i nt i ng namespace.
Step 3: Add a text box and four buttons to the form. We also change the Name and Text
properties of the buttons controls. The final form looks like Figure 6. As you might guess,
the Browse Text File button allows us to browse for text files.



Figure 6: The form with text file printing options

The code for the Browse Text File button is given in Listing 13. This button allows you
to browse a file and adds the selected file name to the text box. Clicking the Print Text
File button prints the selected text file. We use an OpenFi l eDi al og object to open a
text file and set t ext Box1. Text as the selected file name. The functionality of the
Print Text and Print Events buttons is obvious.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 19

Listing 13: The Browse Text File button click event handler

pr i vat e voi d Br owseBt n_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e an OpenFi l eDi al og obj ect
OpenFi l eDi al og Fi l eDl g = new OpenFi l eDi al og( ) ;
/ / Set i t s pr oper t i es
Fi l eDl g. Ti t l e = " C# Cor ner Open Fi l e Di al og" ;
Fi l eDl g. I ni t i al Di r ect or y = @" C: \ " ;
Fi l eDl g. Fi l t er = " Text f i l es ( *. t xt | . t xt | Al l f i l es ( *. *) |
*. *" ;
Fi l eDl g. Fi l t er I ndex = 2;
Fi l eDl g. Rest or eDi r ect or y = t r ue;
/ / Show di al og and set t he sel ect ed f i l e name
/ / as t he t ext of t he t ext box
i f ( Fi l eDl g. ShowDi al og( ) == Di al ogResul t . OK)
{
t ext Box1. Text = Fi l eDl g. Fi l eName;
}
}

Now lets add code for the Print Text File button click. First we add tow private variable
to the application as follows:

pr i vat e Font ver dana10Font ;
pr i vat e St r eamReader r eader ;

Then we proceed as shown in Listing 14. The code is pretty simple. First we make sure
that the user has selected a file name. Then we create a St r eamReader object and read
the file by passing the file name as the only argument. Next we create a font with font
family Verdana and size 10. After that we create a Pr i nt Document object, and a
Pr i nt Page event handler, and call the Pr i nt method. The rest is done by the
Pr i nt Page event handler.

NOTE

The St r eamReader class is defined in the Syst em. I O namespace.

Listing 14: The Print Text File button click event handler

pr i vat e voi d Pr i nt Text Fi l e_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Get t he f i l e name
st r i ng f i l ename = t ext Box1. Text . ToSt r i ng( ) ;
/ / check i f i t s not empt y
i f ( f i l ename. Equal s( st r i ng. Empt y) )
{
MessageBox. Show( " Ent er a val i d f i l e name" ) ;
t ext Box1. Focus( ) ;
r et ur n;
}
/ / Cr eat e a St r eamReader obj ect
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 20

r eader = new St r eamReader ( f i l ename) ;
/ / Cr eat e a Ver dana f ont wi t h si ze 10
ver dana10Font = new Font ( " Ver dana" , 10) ;
/ / Cr eat e a Pr i nt Document obj ect
Pr i nt Document Pr i nt Doc= new Pr i nt Document ( ) ;
/ / Add Pr i nt Page event handl er
Pr i nt Doc. Pr i nt Page += new Pr i nt PageEvent Handl er
( t hi s. Pr i nt Text Fi l eHandl er ) ;
/ / Cal l Pr i nt Met hod
Pr i nt Doc. Pr i nt ( ) ;
/ / Cl ose t he r eader
i f ( r eader ! = nul l )
r eader . Cl ose( ) ;
}

The code for the Pr i nt Page event handler Pr i nt Text Fi l eHandl er is given in
Listing 15. Here we read one line at a time from the text file, using the
St r eamReader . ReadLi ne method, and call Dr awSt r i ng, which prints each line
until we reach the end of the file. To give the text a defined size, we use the
ver dana10Font . Get Hegi ht method.

Listing 15: Adding a print event handler

pr i vat e voi d Pr i nt Text Fi l eHandl er ( obj ect sender , Pr i nt PageEvent Ar gs
ppeAr gs)
{
/ / Get t he Gr aphi cs obj ect
Gr aphi cs g = ppeAr gs. Gr aphi cs;
f l oat l i nesPer Page = 0;
f l oat yPos = 0;
i nt count = 0;
/ / Read mar gi ns f r omPr i nt PageEvent Ar gs
f l oat l ef t Mar gi n = ppeAr gs. Mar gi nBounds. Lef t ;
f l oat t opMar gi n = ppeAr gs. Mar gi nBounds. Top;
st r i ng l i ne = nul l ;
/ / Cal cul at e t he l i nes per page on t he basi s of t he hei ght of t he
page and t he hei ght of t he f ont
l i nesPer Page = ppeAr gs. Mar gi nBounds. Hei ght /
ver dana10Font . Get Hei ght ( g) ;
/ / Now r ead l i nes one by one, usi ng St r eamReader
whi l e ( count < l i nesPer Page &&
( ( l i ne = r eader . ReadLi ne( ) ) ! = nul l ) )
{
/ / Cal cul at e t he st ar t i ng posi t i on
yPos = t opMar gi n + ( count *
ver dana10Font . Get Hei ght ( g) ) ;
/ / Dr aw t ext
g. Dr awSt r i ng( l i ne, ver dana10Font , Br ushes. Bl ack,
l ef t Mar gi n, yPos, new St r i ngFor mat ( ) ) ;
/ / Move t o next l i ne
count ++;
}
/ / I f Pr i nt PageEvent Ar gs has mor e pages t o pr i nt
i f ( l i ne ! = nul l )
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 21

ppeAr gs. HasMor ePages = t r ue;
el se
ppeAr gs. HasMor ePages = f al se;
}

You should be able to add code for the Print Text and Print Events buttons yourself.
Their functionality should be obvious.

Now run the application, browse a text file, and hit the Print Text File button, and you
should be all set.

Printing Graphics Shapes and Images

Printing graphics shapes such as rectangles, ellipses, lines, paths, and polygons is as
simple as drawing them. In this section, we will create an application that shows how to
print simple graphics shapes such as lines, curves, rectangles, and images.

We create a Windows application and add a main menu to the form. We add four menu
items to the main menu. The final form looks like Figure 7. As you might guess, the
Draw Shapes and View Image menu items will draw graphics objects and show an
image, respectively. The Print Image and Print Shapes menu items will print the image
and the graphics items, respectively.

The next step is to add a reference to the Syst em. Dr awi ng. Pr i nt i ng namespace.

Printing Graphics Shapes

Now lets add code on Draw and Print menu items. On Draw Shapes menu item, we add
code listed in Listing 16. This menu item draws two lines, a rectangle, and an ellipse.
First we create a Gr aphi cs object using the For m. Cr eat eGr aphi cs method and
call the Dr awLi ne, Dr awRr ct angl e, and Fi l l El l i pse methods.

Listing 16: Drawing graphics items

pr i vat e voi d Dr awI t ems_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e a Gr aphi cs obj ect
Gr aphi cs g = t hi s. Cr eat eGr aphi cs( ) ;
g. Cl ear ( t hi s. BackCol or ) ;
/ / Dr aw gr aphi cs i t ems
g. Dr awLi ne( Pens. Bl ue, 10, 30, 10, 100) ;
g. Dr awLi ne( Pens. Bl ue, 10, 30, 100, 30) ;
g. Dr awRect angl e( Pens. Red, 30, 50, 200, 180) ;
g. Fi l l Rect angl e( Br ushes. Bl ueVi ol et , 70, 90, 120, 100) ;
/ / Di spose of obj ect
g. Di spose( ) ;
}

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 22



Figure 7: A graphics-printing application

Figure8 shows the output from Listing 16.

Now lets write code for Print Shapes. We want to print the output shown in Figure 8.
We create a Pr i nt Document object, and add a Pr i nt Page event handler, and call
the Pr i nt method. The Pr i nt Page event handler draws the graphics items.

Listing 17 contains two methods. The Pr i nt Gr aphi csI t ems_Cl i ck method is a
menu click event handler that creates a Pr i nt Document object, sets its Pr i nt Page
event, and calls the Pr i nt method. The second method
Pr i nt Gr aphi csI t emsHandl er , simply calls the draw and fill methods of
Pr i nt PageEvent Ar gs. Gr aphi cs.



Figure 8 Drawing graphics shapes
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 23

Listing 17: Printing shapes

pr i vat e voi d Pr i nt Gr aphi csI t ems_Cl i ck ( obj ect sender , Syst em. Event Ar gs
e)
{
/ / Cr eat e a Pr i nt Document obj ect
Pr i nt Document pr i nt Dc = new Pr i nt Document ( ) ;
/ / Add Pr i nt Page event handl er
pr i nt Dc. Pr i nt Page += new Pr i nt PageEvent Handl er
( t hi s. Pr i nt Gr aphi csI t emsHandl er ) ;
/ / Pr i nt
pr i nt Dc. Pr i nt ( ) ;
}
pr i vat e voi d Pr i nt Gr aphi csI t emsHandl er ( obj ect sender ,
Pr i nt PageEvent Ar gs ppeAr gs)
{
/ / Cr eat e a pr i nt er Gr aphi cs obj ect
Gr aphi cs g = ppeAr gs. Gr aphi cs;
/ / Dr aw gr aphi cs i t ems
g. Dr awLi ne( Pens. Bl ue, 10, 10, 10, 100) ;
g. Dr awLi ne( Pens. Bl ue, 10, 10, 100, 10) ;
g. Dr awRect angl e( Pens. Yel l ow, 20, 20, 200, 200) ;
g. Fi l l El l i pse( Br ushes. Gr ay, 40, 40, 100, 100) ;
}

Printing Images

Similarly, the Dr awI mage method of Pr i nt PageEvent Ar gs. Gr aphi cs prints an
image to the printer, which then prints that image onto paper.

Before we add code for the View Image menu item, we need to add two application
scope variables as follows:

pr i vat e I mage cur I mage = nul l ;
pr i vat e st r i ng cur Fi l eName = nul l ;

View Image lets us browse for an image and then draws it on the form. As Listing 18
shows, we create a Gr aphi cs object using For m. Cr eat eGr aphi cs. Then we use
OpenFi l eDi al og to browse files on the system. Once a file has been selected, we
create the Image object by using I mage. Fr omFi l e, which takes the file name as its
only parameter. Finally, we use Dr awI mage to draw the image.

Listing 18: Viewing an image

pr i vat e voi d Vi ewI mage_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e a Gr aphi cs obj ect
Gr aphi cs g = t hi s. Cr eat eGr aphi cs( ) ;
g. Cl ear ( t hi s. BackCol or ) ;
/ / Cal l OpenFi l eDi al og, whi ch al l ows t o br owse i mages
OpenFi l eDi al og OpnDl g = new OpenFi l eDi al og( ) ;
OpnDl g. Fi l t er = " Al l I mage f i l es | *. bmp; *. gi f ; *. j pg; *. i co; " +
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 24

" *. emf , . wmf | Bi t map f i l es ( . bmp; *. gi f ; *. j pg; " +
" *. i co) | *. bmp; *. gi f ; *. j pg; *. i co | " +
" Met a Fi l es ( *. emf ; *. wmf ) | *. emf ; *. wmf " ;
st r i ng f i l t er = OpnDl g. Fi l t er ;
/ / Set I ni t i al Di r ect or y, Ti t l e, and ShowHel p pr oper t i es
OpnDl g. I ni t i al Di r ect or y =
Envi r onment . Cur r ent Di r ect or y;
OpnDl g. Ti t l e = " Open I mage Fi l e" ;
OpnDl g. ShowHel p = t r ue;
/ / I f OpenFi l eDi al og i s OK
i f ( OpnDl g. ShowDi al og( ) == Di al ogResul t . OK)
{
/ / Get t he f i l e name
Cur r ent FName = OpnDl g. Fi l eName;
/ / Cr eat e an I mage obj ect f r omf i l e name
Cur r ent I mg = I mage. Fr omFi l e( Cur r ent FName) ;
}
i f ( Cur r ent I mg ! = nul l )
{
/ / Dr aw i mage usi ng t he Dr awI mage met hod
g. Dr awI mage( Cur r ent I mg, Aut oScr ol l Posi t i on. X,
Aut oScr ol l Posi t i on. Y, Cur r ent I mg. Wi dt h, Cur r ent I mg. Hei ght ) ;
}
/ / Di spose of obj ect
g. Di spose( ) ;
}

Now we run the application and select an image. Figure 9 shows the output.

Now lets write a Print Image item click handler. This option prints an image that were
currently viewing on the form. As in the previous example, we create a
Pr i nt Document , add a Pr i nt Page event handler, and call the Pr i nt method. This
time, however, instead of using the Dr awRect angl e and Dr awLi ne methods, we us
the Dr awI mage method, which draws the image.

As Listing 19 shows, our code creates a Pr i nt Document object, sets the Pr i nt Page
event of Pr i nt Document and the Pr i nt Page event handler, and calls
Pr i nt Document . Pr i nt . The Pr i nt Page event handler calls Dr awI mage.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 25



Figure 9: Viewing an image

Listing 19: Printing an image

pr i vat e voi d Pr i nt I mage_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e a Pr i nt Document obj ect
Pr i nt Document pr i nt Dc = new Pr i nt Document ( ) ;
/ / Add t he Pr i nt Page event handl er
pr i nt Dc. Pr i nt Page += new Pr i nt PageEvent Handl er
( t hi s. Pr i nt I mageHandl er ) ;
/ / Pr i nt
pr i nt Dc. Pr i nt ( ) ;
}

pr i vat e voi d Pr i nt I mageHandl er ( obj ect sender , Pr i nt PageEvent Ar gs
ppeAr gs)
{
/ / Get t he Gr aphi cs obj ect f r omPr i nt PageEvent Ar gs
Gr aphi cs g = ppeAr gs. Gr aphi cs;
/ / I f Gr aphi cs obj ect exi st s
i f ( Cur r ent I mg ! = nul l )
{
/ / Dr aw i mage usi ng t he Dr awI mage met hod
g. Dr awI mage( Cur r ent I mg, 0, 0,
Cur r ent I mg. Wi dt h, Cur r ent I mg. Hei ght ) ;
}
}

If we run the application, open and view a file, and click the Print Image menu item, we
get a printout that looks like Figure 9.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 26

Understanding Print Dialogs

Print Dialog controls are defined in the Syst em. Wi ndows. For ms namespace. Before
using Print dialog controls, you must import this namespace. In this section, we will talk
about following print dialog controls:

Pr i nt Di al og
Pr i nt Pr i vi ewDi al og
Pr i nt Pr i vi ewCont r ol
PageSet upDi al og

The PrintDialog Control

The Pr i nt Di al og class represents the Pr i nt Di al og control in the .NET
Framework library. This class represents a standard Windows printer dialog, which
allows the user to select a printer and choose which portions of the document to print.
Table 4 describes the Pr i nt Di al og class properties. By default, all of these properties
are f al se when a Pr i nt Di al og object is created, and all the properties have both get
and set options.

Beside the properties defined in Table 4, Pr i nt Di al og has on method called Reset .
This method resets all options, the last selected printer, and the page settings to their
default values.

Listing 20 creates a Pr i nt Di al og object, sets it properties, calls ShowDi al og and
prints the document.

Listing 20: Create and using the PrintDialog control

Pr i nt Di al og pr i nt Dl g = new Pr i nt Di al og( ) ;
Pr i nt Document pr i nt Doc = new Pr i nt Document ( ) ;
pr i nt Doc. Document Name = " Pr i nt Document " ;
pr i nt Dl g. Document = pr i nt Doc;
pr i nt Dl g. Al l owSel ect i on = t r ue;
pr i nt Dl g. Al l owSomePages = t r ue;
/ / Cal l ShowDi al og
i f ( pr i nt Dl g. ShowDi al og( ) == Di al ogResul t . OK)
pr i nt Doc. Pr i nt ( ) ;

Table 4: PrintDialog properties

Property Description
Al l owSel ect i on Indicates whether the From... To.., Page option button is
enabled.
Al l owSomePages Indicates whether the Pages option button is enabled.
Document
Identifies the Pr i nt Document object used to obtain
printer settings.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 27

Property Description
Pr i nt er Set t i ngs Identifies the printer settings that the dialog box
modifies.
Pr i nt ToFi l e Indicates whether the Print to file check box is checked.
ShowHel p Indicates whether the Help button is displayed.
ShowNet wor k Indicates whether the Network button is displayed.


The PageSetupDialog Control

The PageSet upDi al og class represents the PageSet upDi al og control in the
.NET Framework library. This class represents a standard Windows page setup dialog
that allows users to manipulate page settings, including margins and paper orientation.
Users can also set a PageSet t i ngs object through PageSet upDi al og s
PageSet t i ngs property. Table 5 describes the properties of the PageSet upDi al og
class. All of these properties have both get the set options.

As with Pr i nt Di al og, the PageSet updi al og class has a Reset method that
resets all the default values for the dialog.

Listing 21 creates a PageSet upDi al og object, sets its properties, calls
ShowDi al og, and prints the document.

Table 5: PageSetupDialog properties

Property Description
Al l owMar gi ns Indicates whether the margins section of the dialog box is
enabled. By default, true when a PageSet upDi al og object
is created.
Al l owOr i ent at i on Indicates whether the orientation section of the dialog box
(landscape versus portrait) is enabled. By default, t r ue when
a PageSet upDi al og object is created.

Al l owPaper Indicates whether the paper section of the dialog box (paper
size and paper source) is enabled. By default, t r ue when a
PageSet upDi al og object is created.
Al l owPr i nt er Indicates whether the Printer button is enabled. By default
t r ue when a PageSet upDi al og object is created.
Document
Identifies the Pr i nt Document object from which to get
page settings. By default, nul l when a
PageSet upDi al og object is created.
Mi nMar gi ns Indicates the minimum margins the user is allowed to select,
in hundredths of an inch. By default, nul l when a
PageSet upDi al og object is created.
PageSet t i ngs
Identifies the page settings to modify. By default, nul l when
a PageSet upDi al og object is created.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 28

Property Description
Pr i nt er Set t i ngs Identifies the printer settings that the dialog box will modify
when the user clicks the Printer button. By default nul l
when a PageSet upDi al og object is created.
ShowHel p Indicates whether the Help button is visible. By default,
f al se when a PageSet upDi al og object is created.
ShowNet wor k Indicates whether the Network button is visible. By default,
t r ue when a PageSet upDi al og object is created.


Listing 21: Creating and using the PageSetupDialog control

set upDl g = new PageSet upDi al og ( ) ;
pr i nt Dl g = new Pr i nt Di al og ( ) ;
pr i nt Doc = new Pr i nt Document ( ) ;
pr i nt Doc. Document Name = " Pr i nt Document " ;
/ / PageSet upDi al og set t i ngs
set upDl g. Document = pr i nt Doc;
set upDl g. Al l owMar gi ns = f al se;
set upDl g. Al l owOr i ent at i on = f al se;
set upDl g. Al l owPaper = f al se;
set upDl g. Al l owPr i nt er = f al se;
set upDl g. Reset ( ) ;

i f ( set upDl g. ShowDi al og( ) == Di al ogResul t . OK)
{
pr i nt Doc. Def aul t PageSet t i ngs =
set upDl g. PageSet t i ngs;
pr i nt Doc. Pr i nt er Set t i ngs =
set upDl g. Pr i nt er Set t i ngs;
}

The PrintPreviewDialog Control

The Pr i nt ePr evi ewDi al og class represents the Pr i nt Pr evi ewDi al og control
in the .NET Framework library. This class represents a standard Windows print preview
dialog, which allows users to preview capabilities before printing. The
Pr i nt Pr evi ewDi al og class is inherited from the For mclass, which means that this
dialog contains all the functionality defined in For m, Cont r ol , and other base
classes.

In addition to the properties provided by the base classes, this class has its own
properties. Many of these properties are very common and are provided by many
controls. Table 6 describers a few important Pr i nt Pr evi ewDi al og class properties.
All of these properties have both get and set options.

Listing 22 creates a Pr i nt Pr evi ewDi al og object, sets its properties calls
ShowDi al og, and prints the document.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 29

Listing 22: Create and using the PrintPreviewDialog control

/ / Cr eat e a Pr i nt Pr evi ewDi al og obj ect
Pr i nt Pr evi ewDi al og pr evi ewDl g = new Pr i nt Pr evi ewDi al og( ) ;
/ / Cr eat e a Pr i nt Document obj ect
Pr i nt Document pr i nt Doc = new Pr i nt Document ( ) ;
/ / Set Document pr oper t y
pr evi ewDl g. Document = pr i nt Doc;
pr evi ewDl g. Wi ndowSt at e = For mWi ndowSt at e. Nor mal ;
/ / show Di al og
pr evi ewDl g. ShowDi al og( ) ;

Table 6: Some PrintPreviewDialog properties

Property Description
Document Identifies the document shown in preview.
Hel pBut t on Indicates whether a help button should be displayed in the
caption box of the form. The default value is f al se.
KeyPr evi ew Indicates whether the form will receive key events before the
event is passed to the control that has focus. The default value
is f al se.
ShowI nTaskbar Indicates whether the form is displayed in the Windows
taskbar. The default value is t r ue.
Tr anspar encyKey Identifies the color that will represent transparent areas of the
form.
UseAnt i Al i as Indicates whether printing uses the anti-aliasing features of the
operating system.
Wi ndowSt at e Identifies the forms window state.


Putting Print Dialogs to Work

Now we are going to create a Windows application that will these print dialog controls.

We create a Windows application and add a Mai nMenu control to the form. We also add
four menu items and a separator to the Mai nMenu control. The final form looks like
Figure 10.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 30



Figure 10: The print dialog application

As usual, our first step is to add some private variable to the project, as follows:

/ / Var i abl e
pr i vat e I mage cur I mage = nul l ;
pr i vat e st r i ng cur Fi l eName = nul l ;
pr i vat e Pr i nt Pr evi ewDi al og pr evi ewDl g = nul l ;
pr i vat e PageSet upDi al og set upDl g = nul l ;
pr i vat e Pr i nt Document pr i nt Doc = nul l ;
pr i vat e Pr i nt Di al og pr i nt Dl g = nul l ;
/ / We al so add t he f ol l owi ng namespace t o t he pr oj ect :
usi ng Syst em. Dr awi ng. Pr i nt i ng;
usi ng Syst em. Dr awi ng. I magi ng;
usi ng Syst em. Dr awi ng. Dr awi ng2D;
usi ng Syst em. Dr awi ng. Text ;

On our forms load event, we initialize these dialogs. We also create a Pr i nt Page
event handler and add it to the Pr i nt Document object, as shown in Listing 23.

Listing 23: Initializing print dialogs

pr i vat e voi d For m1_Load ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e pr i nt pr evi ew di al og and ot her di al ogs
pPr Vi ewDl g = new Pr i nt Pr evi ewDi al og( ) ;
set upDl g = new PageSet upDi al og( ) ;
pr i nt Doc = new Pr i nt Document ( ) ;
pr i nt Dl g = new Pr i nt Di al og( ) ;
/ / Set document name
pr i nt Doc. Document Name = " Pr i nt Document " ;
/ / Pr i nt Pr evi ewDi al og set t i ngs
pPr Vi ewDl g. Document = pr i nt Doc;
/ / PageSet upDi al og set t i ngs
set upDl g. Document = pr i nt Doc;
/ / Pr i nt Di al og set t i ngs
pr i nt Dl g. Document = pr i nt Doc;
pr i nt Dl g. Al l owSel ect i on = t r ue;
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 31

pr i nt Dl g. Al l owSomePages = t r ue;

/ / Cr eat e a Pr i nt Page event handl er
pr i nt Doc. Pr i nt Page += new Pr i nt PageEvent Handl er ( t hi s. pd_Pr i nt ) ;
}

Now we add the Pr i nt Page event handler, which calls Dr awGr aphi csI t ems as
shown in Listing 24. We pass Pr i nt PageEvent Ar gs. Gr aphi cs as the only
parameter to Dr awGr aphi csI t ems.

Listing 24: The PrintPage event handler

pr i vat e voi d pd_Pr i nt ( obj ect sender , Pr i nt PageEvent Ar gs ppeAr gs)
{
Dr awGr aphi csI t ems( ppeAr gs. Gr aphi cs) ;
}

The Dr awGr aphi cs Items method draws an image and text on the printer or the form,
depending on the Gr aphi cs object. If we pass For m. Gr aphi cs, the
Dr awGr aphi csI t ems method will draw graphics objects on the form, but if we pass
Pr i nt PageEvent Ar gs. Gr aphi cs, this method will send drawings to the printer.

The code for the Dr awGr aphi csI t ems method is given in Listing 25. This method
also sets the smoothing mode and text qualities via the Smoot hi ngMode and
Text Render i ngHi nt properties. After that it calls Dr awI mage and Dr awText .

Listing 25: The DrawGraphicsItems method

pr i vat e voi d Dr awGr aphi csI t ems ( Gr aphi cs gobj )
{
/ / Set t ext and i mage qual i t y
gobj . Smoot hi ngMode =
Smoot hi ngMode. Ant i Al i as;
gobj . Text Render i ngHi nt = Text Render i ngHi nt . Ant i Al i as;
i f ( i mage1! = nul l )
{
/ / Dr aw i mage usi ng t he Dr awI mage met hod
gobj . Dr awI mage( i mage1, Aut oScr ol l Posi t i on. X,
Aut oScr ol l Posi t i on. Y, i mage1. Wi dt h, i mage1. Hei ght ) ;
}
/ / Dr aw a st r i ng
gobj . Dr awSt r i ng( " Pr i nt i ng Di al ogs Text " , new Font ( " Ver dana" , 25) ,
new Sol i dBr ush( Col or . Vi ol et ) , 40, 40) ;
}

Theres just one more thing to do before we write the menu item event handlers. We call
Dr awGr aphi csI t ems from the forms paint event handler, as Listing 26 shows.
Adding this code will display the drawing on the form.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 32

Listing 26: The forms paint event handler

pr i vat e voi d For m1_Pai nt ( obj ect sender ,
Syst em. Wi ndows. For ms. Pai nt Event Ar gs e)
{
Dr awGr aphi csI t ems ( e. Gr aphi cs) ;
}

Now we can write code for the menu items. The Open File menu item just let use browse
images and creates an I mage object by calling the I mage. Fr omFi l e method, as
Listing 27 shows.

Listing 27: The Open File menu handler

pr i vat e voi d OpenFi l e_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e a Gr aphi cs obj ect
Gr aphi cs g = t hi s. Cr eat eGr aphi cs( ) ;
g. Cl ear ( t hi s. BackCol or ) ;
/ / Cr eat e open f i l e di al og
OpenFi l eDi al og openDl g = new OpenFi l eDi al og( ) ;
/ / Set f i l t er as i mage
openDl g. Fi l t er =
" Al l I mage f i l es | *. bmp; *. gi f ; *. j pg; *. i co; " +
" *. emf , . wmf | Bi t map Fi l es ( *. bmp; *. gi f ; *. j pg; " +
" *. i co) | *. bmp; *. gi f ; *. j pg; *. i co| " +
" Met a Fi l es ( *. emf ; *. wmf ) | *. emf ; *. wmf " ;
st r i ng f i l t er = openDl g. Fi l t er ;
/ / Set t i t l e and i ni t i al di r ect or y
openDl g. I ni t i al Di r ect or y =
Envi r onment . Cur r ent Di r ect or y;
openDl g. Ti t l e = " Open I mage Fi l e" ;
openDl g. ShowHel p = t r ue;
/ / Show di al og
i f ( openDl g. ShowDi al og( ) == Di al ogResul t . OK)
{
/ / Get t he f i l e name and cr eat e I mage obj ect f r omf i l e
Fi l eName = openDl g. Fi l eName;
i mage1= I mage. Fr omFi l e( Fi l eName) ;
}
i f ( i mage1 ! = nul l )
{
/ / Dr aw i mage usi ng t he Dr awI mage met hod
g. Dr awI mage( i mage1, Aut oScr ol l Posi t i on. X,
Aut oScr ol l Posi t i on. Y,
i mage1. Wi dt h, i mage1. Hei ght ) ;
}
/ / Di spose of obj ect
g. Di spose( ) ;
}

The code for Pr i nt Pr evi ewDi al og, PageSet upDi al og, and Pr i nt Di al og
is given in Listing 28. We show Pr i nt Di al og and call its
Pr i nt Document . Pr i nt method if the user selects OK on the print dialog. We set
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 33

PageSet upDi al og page and printer settings when the user selects OK on the page
setup dialog. For the print preview dialog, we set the UseAnt i Al i as property and call
ShowDi al og.

Listing 28: Print dialogs

pr i vat e voi d Pr i nt Di al og_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
i f ( pr i nt Dl g. ShowDi al og( ) == Di al ogResul t . OK)
pr i nt Doc. Pr i nt ( ) ;
}
pr i vat e voi d PageSet upDi al og_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
i f ( set upDl g. ShowDi al og( ) == Di al ogResul t . OK)
{
pr i nt Doc. Def aul t PageSet t i ngs = set upDl g. PageSet t i ngs;
pr i nt Doc. Pr i nt er Set t i ngs = set upDl g. Pr i nt er Set t i ngs;
}
}
pr i vat e voi d Pr i nt Pr evi ew_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
pPr Vi ewDl g. UseAnt i Al i as = t r ue;
pPr Vi ewDl g. Wi ndowSt at e = For mWi ndowSt at e. Nor mal ;
pPr Vi ewDl g. ShowDi al og( ) ;
}

Now when we run the application and browse an image using the Open File menu item,
the form looks like Figure 11.

If we click on Print Preview, our program will display the print preview dialog, as
shown in Figure 12.

As stated earlier, the page setup dialog allows us to set the page properties, including
size, sources, orientation, and margins. Clicking on Print Setup on the dialog menu
brings up the page setup dialog, which is shown in Figure 13.

We can use these dialogs as we would in any other Windows applications.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 34



Figure 11: Viewing an image and text



Figure 12: The print preview dialog

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 35



Figure 13: The page setup dialog



Figure 14: The print dialog
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 36


Customizing Page Settings

There are times when we may need custom page settings with custom dialogs. For
example, suppose we want to change the text of the dialog or dont want the user to have
page selection or anything else that is not available on the default Windows dialogs.

The Syst em. Dr awi ng. Pr i nt i ng namespace also defines functionality to manage
page settings programmatically.

The PageSettings Class

Page settings are the properties of a page that are being used when a page is printer,
including colors, page margins, paper size, page bounds, and page resolution.

The PageSet t i ngs class represents page settings in the .NET Framework library. This
class provides members to specify page settings. It is used by the
Pr i nt document . Def ul t PageSet t i ngs property to specify the page settings of a
Pr i nt Document object. Table 7 describes the properties of the PageSet t i ngs
class.

Besides the properties described in Table 7, the PageSet t i ngs class provides three
methods: Cl one, CopyToHdevmode, and Set Hdevmode. The Clone method
simply creates a copy of the PageSet t i ngs object. CopyToHdevmode copies
relevant information from the PageSet t i ngs object from the specified DEVMODE
structure, and Set Hdevmode copies relevant information to the PageSet t i ngs
object from the specified DEVMODE structure. The DEVMODE structure is used by WIN32
programmers.

Page Margins

The Mar gi ns class represents a page margin in the .NET Framework library. It allows
you to get the current page margin settings and set new margin settings. This class has
four properties Lef t , Ri ght , Top, and Bot t om which represent the left,
right, top, and bottom margins, respectively, in hundredths of an inch. This class is used
by the Mar gi ns property of the PageSet t i ngs class. We will use this class and its
members in our examples.

Table 7: PageSettings properties

Property Description
Bounds Returns the size of the page.
Col or Indicates whether the page should be printed in color. Both
get and set. The default is determined by the printer.
Landscape Indicates whether the page is printed in landscape or portrait
orientation. Both get and set. The default is determined by
the printer.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 37

Property Description
Mar gi ns Identifies the page margins. Both get and set.
Paper Si ze Identifies the paper size. Both get and set.
Paper Sour ce Identifies the paper source (a printer tray). Both get and set.
Pr i nt er Resol ut i on Identifies the printer resolution for the page. Both get and
set.
Pr i nt er Set t i ngs Identifies the printer settings associated with the page. Both
get and set.


Creating a Custom Paper Size

As mentioned earlier, the Paper Si ze class specifies the size and type of paper. You
can create you own custom paper sizes. For example, Listing 29 creates a custom paper
size with a height of 200 and width of 100.

Listing 29: Creating a custom paper size

/ / Cr eat e a cust ompaper si ze and add i t t o t he l i st
Paper Si ze cust omPaper Si ze = new Paper Si ze( ) ;
cust omPaper Si ze. Paper Name = " Cust omSi ze" ;
cust omPaper Si ze. Hei ght = 200;
cust omPaper Si ze. Wi dt h = 100;

The PaperKind Enumeration

The Paper Ki nd enumeration, as we saw earlier, is used by the Ki nd property to
specify standard paper sizes. This enumeration has over 100 members. Among them are
A2, A3, A3Ext r a, A3Ext r aTr ansver se, A3Rot at ed,
A3Tr ansver se, A4, A5, A6, Cust om, DCEnvel ope, Execut i ve,
I nvi t eEnvel ope, I t al yEnvel ope, J apanesePost Car d, Ledger ,
Legal , Legal Ext r a, Let t er , Let t er Ext r a, Let t er Smal l ,
St andar d10x11 ( 10x14, 10x17, 12x11, 15x11, 9x11) ,
St at ement , and Tabl oi d.

The PaperSourceKind Enumeration

The Paper Sour ceKi nd enumeration represents standard paper sources. Table 8
describes the members of the Paper Sour ceKi nd enumeration.

Table 8: PaperSoruceKind members

Member Description
Aut omat i cFeed Automatically fed paper
Casset t e A paper cassette
Cust om A printer-specific paper source
Envel ope An Envelope
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 38

Member Description
For mSour ce The printers default input bin
Lar geCapaci t y The printers large-capacity bin
Lar geFor mat Large-format paper
Lower The lower bin of a printer
Manual Manually fed paper
Manual Feed Manually fed envelope
Mi ddl e The middle bin of a printer
Smal l For mat Small-format paper
Tr act or Feed A tractor feed
Upper The upper bin of a printer


Page Settings Example

Now lets see how we can create an application that will allow us to get and set page
settings. In this application we will create a custom dialog.

We start by creating a new Windows application in VS .NET. We add some controls to
the form, with the result shown in Figure 15. The Available Printers combo box displays
all available printers. The Size and Source combo boxes display paper sizes and sources,
respectively. The Paper Orientation section indicates whether paper is oriented in
landscape mode or portrait mode. The Paper Margins text boxes obviously represent
left, right, top and bottom margins. The Bounds property is represented by the Bounds
(Rectangle) text box. The Color Printing check box indicates whether the printer
supports color printing. The Set Properties button allows us to enter new values in the
controls.

The forms load event (see Listing 30) loads all the required PageSet t i ngs-related
settings using the LoadPr i nt er s, LoadPaper Si zes, LoadPaper Sour ces,
and ReadOt her Set t i ngs methods.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 39



Figure 15: The custom page settings dialog

Listing 30: The forms load event handler

pr i vat e voi d For m1_Load ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Load al l avai l abl e pr i nt er s
LoadPr i nt er s( ) ;
/ / Load paper si zes
LoadPaper Si zes( ) ;
/ / Load paper sour ces
LoadPaper Sour ces( ) ;
/ / Load ot her set t i ngs
ReadOt her Set t i ngs( ) ;
}

The LoadPr i nt er s, LoadPaper Si zes, LoadPaper Sour ces, and
ReadOt her Set t i ngs methods are used to load printers, paper sizes, paper sources,
and other properties, respectively. The LoadPr i nt er s method is given in Listing 31.
We simply read the I nst al l edPr i nt er s property of Pr i nt er Set t i ngs and add
printer to the pr i nt er sLi st combo box.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 40

Listing 31: Loading printers

pr i vat e voi d LoadPr i nt er s( )
{
/ / Load al l avai abl e pr i nt er s
f or each ( St r i ng pr i nt er i n
Pr i nt er Set t i ngs. I nst al l edPr i nt er s)
{
pr i nt er sLi st . I t ems. Add( pr i nt er . ToSt r i ng( ) ) ;
}
pr i nt er sLi st . Sel ect ( 0, 1) ;
}

The LoadPaper Si zes method (see Listing 32), loads all available paper sizes to the
combo box. We read the Paper Si zes property of Pr i nt er Set t i ngs and add the
paper type to the combo box. Then we create a custom paper size and add this to the
combo box as well. This example will give you an idea of how to create your own custom
paper sizes.

Listing 32: Loading paper sizes

pr i vat e voi d LoadPaper Si zes( )
{
Paper Si zeCombo. Di spl ayMember = " Paper Name" ;
Pr i nt er Set t i ngs Pr Set t i ng = new Pr i nt er Set t i ngs( ) ;
/ / Get al l paper si zes and add t hemt o t he combo box l i st
f or each ( Paper Si ze si ze i n Pr Set t i ng. Paper Si zes)
{
Paper Si zeCombo. I t ems. Add( si ze. Ki nd. ToSt r i ng( ) ) ;
/ / You can even r ead t he paper name and al l Paper Si ze pr oper t i es
by uncomment i ng t hese t wo l i nes:
Paper Si zeCombo. I t ems. Add( si ze. Paper Name. ToSt r i ng( ) ) ;
Paper Si zeCombo. I t ems. Add( si ze. ToSt r i ng( ) ) ;
}
/ / Cr eat e a cust ompaper si ze and add i t t o t he l i st
Paper Si ze cust omPaper Si ze = new Paper Si ze( " Cust omSi ze" , 50, 100) ;
/ / You can al so change pr oper t i es
cust omPaper Si ze. Paper Name = " New Cust o, Si ze" ;
cust omPaper Si ze. Hei ght = 200;
cust omPaper Si ze. Wi dt h = 100;
/ / Don t assi gn t he Ki nd pr oper t y. I t s r ead- onl y.
/ / cust omPaper Si ze. Ki nd = Paper Ki nd. A4;
/ / Add cust omsi ze
Paper Si zeCombo. I t ems. Add( cust omPaper Si ze) ;
}

The LoadPaper Sour ces methods (see Listing 33), reads all available paper sources
and adds them to the Paper Sour ceCombo combobox. We use the Paper Sor uces
property of Pr i nt er Set t i ngs to read the paper sources.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 41

Listing 33: Loading paper sources

pr i vat e voi d LoadPaper Sour ces( )
{
Pr i nt er Set t i ngs Pr Set t i ng = new Pr i nt er Set t i ngs( ) ;
Paper Sour ceCombo. Di spl ayMember = " Sour ceName" ;
/ / Add al l paper sour ces t o t he combo box
f or each ( Paper Sour ce sour ce i n Pr Set t i ng. Paper Sour ces)
{
Paper Sour ceCombo. I t ems. Add( sour ce. ToSt r i ng( ) ) ;
/ / You can even add Ki nd and Sour ceName
/ / by uncomment i ng t he f ol l owi ng t wo l i nes:
/ / Paper Sour ceCombo. I t ems. Add
/ / ( Sour ce. Ki nd. ToSt r i ng( ) ) ;
/ / Paper Sour ceCombo. I t ems. Add
/ / ( sour ce. Sour ceName. ToSt r i ng( ) ) ;
}
}

The last method, ReadOt her Set t ni gs, reads other properties of a printer, such as
whether it supports color, margins, and bounds. Listing 34 shows the
ReadOt her Set t i ngs method.

Listing 34: Loading other properties of a printer

pr i vat e voi d ReadOt her Set t i ngs( )
{
/ / Set ot her def aul t pr oper t i es
Pr i nt er Set t i ngs Pr Set t i ng = new Pr i nt er Set t i ngs( ) ;
PageSet t i ngs pgSet t i ngs =
Pr Set t i ng. Def aul t PageSet t i ngs;
/ / Col or pr i nt i ng
i f ( pgSet t i ngs. Col or )
Col or Pr i nt i ngBox. Checked = t r ue;
el se
Col or Pr i nt i ngBox. Checked = f al se;

/ / Page mar gi ns
l ef t Mar gi nBox. Text = pgSet t i ngs. Bounds. Lef t . ToSt r i ng( ) ;
r i ght Mar gi nBox. Text = pgSet t i ngs. Bounds. Ri ght . ToSt r i ng( ) ;
t opMar gi nBox. Text = pgSet t i ngs. Bounds. Top. ToSt r i ng( ) ;
bot t omMar gi nBox. Text = pgSet t i ngs. Bounds. Bot t om. ToSt r i ng( ) ;

/ / Landscape or por t r ai t
i f ( pgSet t i ngs. Landscape)
l andscapeBut t on. Checked = t r ue;
el se
por t r ai t But t on. Checked = t r ue;
/ / Bounds
boundsText Box. Text =
pgSet t i ngs. Bounds. ToSt r i ng( ) ;
}


Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 42



Figure 16: The PageSetupDialog sample in action

Now if we run the application, its form looks like Figure 16. Each of the Windows
controls displays its intended property.

Finally, we want to save settings through the Set Properties button click and write code
for a Cancel button. On the Set Properties button click, we set the properties using
Pr i nt er Set t i ngs. Make sure printer is available in the Available Printers combo
box. The Cancel button simply closes the dialog.

The code for the Set Properties and Cancel button click event handlers is given in
Listing 35, in which we set the page settings, color, and landscape properties of a page.

Listing 35: Saving paper settings

pr i vat e voi d Set Pr oper t i esBt n_cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Set ot her def aul t pr oper t i es
Pr i nt er Set t i ngs Pr Set t i ng = new Pr i nt er Set t i ngs( ) ;
PageSet t i ngs pgSet t i ngs =
Pr Set t i ng. Def aul t PageSet t i ngs;
/ / Col or pr i nt i ng?
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 43

i f ( Col or Pr i nt i ngBox. Checked)
pgSet t i ngs. Col or = t r ue;
el se
pgSet t i ngs. Col or = f al se;

/ / Landscape or por t r ai t ?

i f ( l andscapeBut t on. Checked)
pgSet t i ngs. Landscape = t r ue;
el se
pgSet t i ngs. Landscape = f al se;
}
pr i vat e voi d but t on2_Cl i ck( obj ect sender , Event Ar gs e)
{
t hi s. Cl ose( ) ;
}

The preceding discussion should enable you to customize page settings in the way that
you want, instead of using the standard page settings dialog provided in the
PageSet t i ngsDi al og class.

NOTE

Even though the printing facility defined in the Syst em. Dr awi ng. Pr i nt i ng
namespace allows developers to customize the standard Windows dialogs, I recommend
that you use the standard Windows dialogs unless you cant live without customizing
them.

The PrintRange Enumeration

The Pr i nt Range enumeration is used to specify the part of a document to print. This
enumeration is used by the Pr i nt er Set t i ngs and Pr i nt Di al og classes. Table 9
describes the members of the Pr i nt Range enumeration.

You can use the Pr i nt Range property of the Pr i nt er Set t i ngs object to set the
print range. Heres an example of code that does this:

Pr i nt er Set t i ngs. Pr i nt Range = Pr i nt Range. SomePages;

Table 9: PrintRange members

Member Description
Al l Pages All pages are printed.
Sel ect i on The selected pages are printed.
SomePages The pages between FromPage and ToPage are printed.


Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 44

Printing Multiple Page Documents

So far we have discussed printing only an image or a single-page file. Printing multipage
files is another important part of printing functionality that developers may need to
implement when writing printer applications. Unfortunately, the .NET Framework does
not keep track of page numbers for you, but it provides enough support for you to keep
track of the current page, the total number of pates, the last page, and a particular page
number. Basically, when printing a multipage document, you need to find out the total
number of pages and print them from first to last. You can also specify a particular page
number. If you are using the default Windows printing dialog, then you dont have to
worry about it because you can specify the pages in the dialog, and the framework takes
care of this for you.

To demonstrate how to do this, our next programs produces a useful printout showing all
the fonts installed on your computer. This program is a useful tool for demonstrating the
calculation of how many pages to print when youre using graphical commands to print.

We will use the Pr i nt Pr evi ew facility to display the output in case you dont have
access to a printer and how far down the page we are. If were going to go over the end of
the page, we drop out of the pd_Pr i nt Page event handler and set
ev. HasMor ePages to t r ue to indicate that we have another page to print.

To see this functionality in action, lets create a Windows application and add a menu
with three menu items and a Ri chText Box control to the form. The final form is
shown in Figure 17.



Figure 17: A form for printing multiple pages

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 45

The Display Fonts menu display available fonts on the machine. Before we add code to
this menu, we add the following variables:

pr i vat e i nt f ont count ;
pr i vat e i nt f ont posi t i on = 1;
pr i vat e f l oat ypos = 1;
pr i vat e Pr i nt Pr evi ewDi al og pr evi ewDl g = nul l ;

The code for the Display Fonts menu click is given in Listing 36. Here we read installed
fonts on the system and display them in the rich text box. We use
I nst al l edFont Col l ect i on to read all installed fonts on a machine. Then we use
the I nst al l edFont Col l ect i on. Fami l i es property and make a loop to read all
the font families. We also check if these families support different styles, including
regular, bold, italic, and underline, and wee add some text to the rich text box with the
current font.

Listing 36: Displaying fonts

pr i vat e voi d Di spl ayFont s_Cl i ck_1 ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e I nst al l edFont Col l ect i on obj ect s
I nst al l edFont Col l ect i on i nsFont Col l = new
I nst al l edFont Col l ect i on( ) ;

/ / Get f ont f ami l i es
Font Fami l y[ ] f f s = i nsFont Col l . Fami l i es;
Font f ;
/ / Make sur e r i ch t ext box i s empt y
r i chText Box1. Cl ear ( ) ;
/ / Read f ont f ami l i es one by one,
/ / set f ont t o some t ext ,
/ / and add t ext t o t he t ext box
f or each ( Font Fami l y Font Fml y i n f f s)
{
i f ( Font Fml y. I sSt yl eAvai l abl e( Font St yl e. Regul ar ) )
f = new Font ( Font Fml y. Get Name( 1) , 12, Font St yl e. Regul ar ) ;
el se i f ( Font Fml y. I sSt yl eAvai l abl e( Font St yl e. Bol d) )
f = new Font ( Font Fml y. Get Name( 1) , 12, Font St yl e. Bol d) ;
el se i f ( Font Fml y. I sSt yl eAvai l abl e( Font St yl e. I t al i c) )
f = new Font ( Font Fml y. Get Name( 1) , 12, Font St yl e. I t al i c) ;
el se
f = new Font ( Font Fml y. Get Name( 1) , 12, Font St yl e. Under l i ne) ;
r i chText Box1. Sel ect i onFont = f ;
r i chText Box1. AppendText ( Font Fml y. Get Name( 1) + " \ r \ n" ) ;
r i chText Box1. Sel ect i onFont = f ;
r i chText Box1. AppendText ( " abcdef ghi j kl mnopqr st uvwxyz\ r \ n" ) ;
r i chText Box1. Sel ect i onFont = f ;
r i chText Box1. AppendText ( " ABCDEFGHI J KLMNOPQRSTUVWXYZ\ r \ n" ) ;
r i chText Box1. AppendText ( " ==========================\ r \ n" ) ;
}
}

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 46

The code for the Print Preview and Print menu items is given in Listing 37. This code
should look familiar to you. We simply create Pr i nt Document and
Pr i nt Pr evi ewDi al og objects, set their properties, add a print-page event handler,
and call the Pr i nt and Show methods.

Listing 37: The Print Preview and Print menu items

pr i vat e voi d Pr i nt Pr evi ewMenuCl i ck ( obj ect sender , Syst em. Event Ar gs e)
{

/ / Cr eat e a Pr i nt Pr evi ewDi al og obj ect
pr evi ewDl g = new Pr i nt Pr evi ewDi al og( ) ;
/ / Cr eat e a Pr i nt Document obj ect
Pr i nt Document Pr i nt Dc = new Pr i nt Document ( ) ;
/ / Add pr i nt - page event handl er
Pr i nt Dc. Pr i nt Page +=new Pr i nt PageEvent Handl er ( Pr i nt Dc_Pr i nt Page) ;
/ / Set Document pr oper t y of Pr i nt Pr evi ewDi al og
pr evi ewDl g. Document = Pr i nt Dc;
/ / Di spl ay di al og
pr evi ewDl g. Show( ) ;
}

pr i vat e voi d Pr i nt MenuCl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e a Pr i nt Pr evi ewDi al og obj ect
pr evi ewDl g = new Pr i nt Pr evi ewDi al og( ) ;
/ / Cr eat e a Pr i nt Document obj ect
Pr i nt Document Pr i nt Dc = new Pr i nt Document ( ) ;
/ / Add pr i nt - page event handl er
Pr i nt Dc. Pr i nt Page +=
new Pr i nt PageEvent Handl er ( Pr i nt Dc_Pr i nt Page) ;
/ / Pr i nt
Pr i nt Dc. Pr i nt ( ) ;
}

The print-page event handler, pd_Pr i nt Page, is given in Listing 38. We print fonts
using Dr awSt r i ng, and we set Pr i nt PageEvent Ar gs. HasMor ePages to t r ue.
To make sure the text fits, we increase the y-position by 60 units.

Listing 38: The print-page event handler

publ i c voi d pd_Pr i nt Page ( obj ect sender , Pr i nt PageEvent Ar gs ev)
{
ypos = 1;
f l oat pagehei ght = ev. Mar gi nBounds. Hei ght ;
/ / Cr eat e a Gr aphi cs obj ect
Gr aphi cs g = ev. Gr aphi cs;
/ / Get i nst al l ed f ont s
I nst al l edFont Col l ect i on i nsFont Col l = new
I nst al l edFont Col l ect i on( ) ;

/ / Get f ont f ami l i es
Font Fami l y[ ] f f s = i nsFont Col l . Fami l i es;
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 47

/ / Dr aw st r i ng on t he paper
whi l e ( ypos + 60 < pagehei ght && f ont posi t i on < f f s. Get Lengt h( 0) )
{
/ / Get t he f ont name
Font f = new Font ( f f s[ f ont posi t i on] . Get Name( 0) , 25) ;
/ / Dr aw st r i ng
g. Dr awSt r i ng( f f s[ f ont posi t i on] . Get Name( 0) , f , new
Sol i dBr ush( Col or . Bl ack) , 1, ypos) ;
f ont posi t i on = f ont posi t i on + 1;
ypos = ypos + 60;
}
i f ( f ont posi t i on < f f s. Get Lengt h( 0) )
{
/ / Has mor e pages??
ev. HasMor ePages = t r ue;
}
}

Thats it. If we run the program, the Print menu prints multiple pages, and the Print
Preview menu shows the print preview on two pages (see Figure 18).

As you can see, its pretty easy to create multipage report generators. Now you can use
the print option to print documents with multiple pages.

The DocumentName Property

If you want to display the name of the document youre printing, you can use the
Document Name property of the Pr i nt Document object:

pd. Document Name =" A Text Document " ;

The new result is shown in Figure 19.

We have seen that using the Document Pr i nt Pr evi ew class is fairly straightforward.
In reality, all thats happening is that this control is passed a graphics class representing
each page in a printout.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 48



Figure 18: Print preview of multiple pages



Figure 19: Setting a document name

Marginal Printing: A Caution

Although its exciting to be able to draw graphics on a printout, keep in mind that printers
have limits. Never try to print at the extreme edges page because you cannot be sure that
a printer will print in exactly the same place. You could have two printers of the same
model and manufacturer and yet when you print you may notice they print in different
places. Some printers are more accurate than others, but usually a sheet of paper will
move slightly as it moves through the printer. Laser printers tend to be able to print closer
to the edges of the paper than inkjet printers because of the mechanism that is used to
transport the sheet of paper thought the printer.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 49

To see a marginal-printing sample, lets create a Windows application. We add two
buttons to the form. The final form is shown in Figure 20.

Now we add code for the Normal Printing and Marginal Printing button click event
handlers, as in Listing 39. Each handler creates a Pr i nt Document object, adds a
Pr i nt Page event handler, and calls the Pr i nt method. The Pr i nt Page event
handlers for Normal Printing and Marginal Printing are Nor mal Pr i nt i ng and
Mar gi nPr i nt i ng, respectively.



Figure 20: Marginal-printing test application

Listing 39: The Normal Printing and Marginal Printing button event handlers

pr i vat e voi d Nor mal Bt n_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e a Pr i nt Document obj ect
Pr i nt Document Pr i nt Dc = new Pr i nt Document ( ) ;
/ / Add Pr i nt Page event handl er
Pr i nt Dc. Pr i nt Page += new Pr i nt PageEvent Handl er ( Nor mal Pr i nt i ng) ;
/ / Pr i nt
Pr i nt Dc. Pr i nt ( ) ;
}

pr i vat e voi d Mar gi nal Bt n_Cl i ck ( obj ect sender , Syst em. Event Ar gs e)
{
/ / Cr eat e a Pr i nt Document obj ect
Pr i nt Document Pr i nt Dc = new Pr i nt Document ( ) ;
/ / Add Pr i nt Page event handl er
Pr i nt Dc. Pr i nt Page +=
new Pr i nt PageEvent Handl er ( Mar gi nPr i nt i ng) ;
/ / Pr i nt
Pr i nt Dc. Pr i nt ( ) ;
}
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 50

Now lets look at the Nor mal Pr i nt i ng handler (see Listing 40). We start with the top
location of the text as unit 1. Then we calculated the nest lines position using the height
of the font and draw lines with the values of the top, left, bottom, and right margins. In
the end we draw a rectangle with the default bounds of the page.

Listing 40: The NormalPrinting event handler

publ i c voi d Nor mal Pr i nt i ng ( obj ect sender , Pr i nt PageEvent Ar gs ev)
{
/ / Set t he t op posi t i on as 1
f l oat ypos = 1;
/ / Get t he def aul t l ef t mar gi n
f l oat l ef t Mar gi n = ev. Mar gi nBounds. Lef t ;
/ / Cr eat e a f ont
Font f ont = new Font ( " Ar i al " , 16) ;
/ / Get t he f ont s hei ght
f l oat f ont hei ght = f ont . Get Hei ght ( ev. Gr aphi cs) ;
/ / Dr aw f our st r i ngs
ev. Gr aphi cs. Dr awSt r i ng( " Top Mar gi n = "
+ ev. Mar gi nBounds. Top. ToSt r i ng( ) ,
f ont , Br ushes. Bl ack,
l ef t Mar gi n, ypos) ;
ypos = ypos + f ont hei ght ;
ev. Gr aphi cs. Dr awSt r i ng( " Bot t omMar gi n = "
+ ev. Mar gi nBounds. Bot t om. ToSt r i ng( ) ,
f ont , Br ushes. Bl ack,
l ef t Mar gi n, ypos) ;
ypos = ypos + f ont hei ght ;
ev. Gr aphi cs. Dr awSt r i ng( " Lef t Mar gi n = "
+ ev. Mar gi nBounds. Lef t . ToSt r i ng( ) ,
f ont , Br ushes. Bl ack,
l ef t Mar gi n, ypos) ;
ypos = ypos + f ont hei ght ;
ev. Gr aphi cs. Dr awSt r i ng( " Ri ght Mar gi n = "
+ ev. Mar gi nBounds. Ri ght . ToSt r i ng( ) ,
f ont , Br ushes. Bl ack,
l ef t Mar gi n, ypos) ;
ypos = ypos + f ont hei ght ;
/ / Dr aw a r ect angl e wi t h def ual t mar gi ns
ev. Gr aphi cs. Dr awRect angl e(
new Pen( Col or . Bl ack) ,
ev. Mar gi nBounds. X,
ev. Mar gi nBounds. Y,
ev. Mar gi nBounds. Wi dt h,
ev. Mar gi nBounds. Hei ght ) ;
}

If we run the application, we will see text describing the four margins values printed
outside the rectangle.

Next comes code for the Mar gi nPr i nt i ng event handler (see Listing 41). We use the
default margin of the page as the top location for the first text. Everything else is the
same as in Listing 40.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 51

Listing 41: The MarginPrinting event handler

publ i c voi d Mar gi nPr i nt i ng ( obj ect sender , Pr i nt PageEvent Ar gs ev)
{
/ / Set t he t op posi t i on as t he def aul t mar gi n
f l oat ypos = ev. Mar gi nBounds. Top;
/ / Get t he def aul t l ef t mar gi n
f l oat l ef t Mar gi n = ev. Mar gi nBounds. Lef t ;
/ / Cr eat e a f ont
Font f ont = new Font ( " Ar i al " , 16) ;
/ / Get t he f ont s hei ght
f l oat f ont hei ght = f ont . Get Hei ght ( ev. Gr aphi cs) ;
/ / Dr aw f our st r i ngs
ev. Gr aphi cs. Dr awSt r i ng( " Top Mar gi n = "
+ ev. Mar gi nBounds. Top. ToSt r i ng( ) ,
f ont , Br ushes. Bl ack,
l ef t Mar gi n, ypos) ;
ypos = ypos + f ont hei ght ;
ev. Gr aphi cs. Dr awSt r i ng( " Bot t omMar gi n ="
+ ev. Mar gi nBounds. Bot t om. ToSt r i ng( ) ,
f ont , Br ushes. Bl ack,
l ef t Mar gi n, ypos) ;
ypos = ypos + f ont hei ght ;
ev. Gr aphi cs. Dr awSt r i ng( " Lef t Mar gi n = "
+ ev. Mar gi nBounds. Lef t . ToSt r i ng( ) ,
f ont , Br ushes. Bl ack,
l ef t Mar gi n, ypos) ;
ypos = ypos + f ont hei ght ;
ev. Gr aphi cs. Dr awSt r i ng( " Ri ght Mar gi n = "
+ ev. Mar gi nBounds. Ri ght . ToSt r i ng( ) ,
f ont , Br ushes. Bl ack,
l ef t Mar gi n, ypos) ;
ypos = ypos + f ont hei ght ;
/ / Dr aw a r ect angl e wi t h def aul t mar gi ns
ev. Gr aphi cs. Dr awRect angl e(
new Pen( Col or . Bl ack) ,
ev. Mar gi nBounds. X,
ev. Mar gi nBounds. Y,
ev. Mar gi nBounds. Wi dt h,
ev. Mar gi nBounds. Hei ght ) ;
}

When we run this code, we will se text appearing inside the rectangle printed using the
page margin values.

Getting into the Details: Custom Controlling and the Print Controller

At this point you must feel like a printer master and have the confidence you need to
write a printing application. We have covered almost every aspect of printing in .NET,
but guess what! There are still a few surprises hidden in
Syst em. Dr awi ng. Pr i nt i ng. You will probably never use the classes that were
going to discuss in this section, but its not a bad idea to know about them.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 52

So far in this article weve created a Pr i nt Document object, created a Pr i nt Page
event handler, and called the Pr i nt method of Pr i nt Document .
Pr i nt Document took care of everything internally for us. Now we will see how to
control Pr i nt Document objects handles printing.

The Pr i nt Cont r ol l er class represents print controllers in the .NET Framework
library. Its an abstract base class, so its functionality comes from its three derived
classes: Pr evi ewPr i nt Cont r ol l er , St andar dPr i nt Cont r ol l er , and
Pr i nt Cont r ol l er Wi t hSt at usDi al og. Pr i nt Cont r ol l er and its derived
classes are shown schematically in Figure 21.

Normally Pr i nt Cont r ol l er is used by Pr i nt Document . When
Pr i nt Document starts printing by calling the Pr i nt method, it invokes the print
controllers OnSt ar t Pr i nt , OnEndPr i nt , OnSt ar t Page, and OnEndPage
methods, which determine how a printer will print the document. Usually the
OnSt ar t Pr i nt method of Pr i nt Cont r ol l er is responsible for obtaining the
Gr aphi cs object, which is later used by the Pr i nt Page event handler.

The St andar dPr i nt Cont r ol l er class is used to send pages to the printer. We set
the Pr i nt Cont r ol l er property of Pr i nt Document to Pr i nt Cont r ol l er .
St andar d- Pr i nt Cont r ol l er . Pr i nt Cont r ol l er Wi t hSt at usDi al og
adds a status dialog to the printing functionality. It shows the name of the document
currently being printed. To attach Pr i nt Cont r ol l er Wi t hSt at usDi al og, we set
Pr i nt Document s Pr i nt Cont r ol l er property to
Pr i nt cont r ol l er . Pr i nt Cont r ol l er Wi t hSt at usDi al og.



Figure 21: PrintController-derived classes

The Pr evi ewPr i nt Cont r ol l er class is used for generating previews of pages
being printed. Beside the methods defined in the Pr i nt Cont r ol l er class,
Pr evi ewPr i nt Cont r ol l er provides one property (UseAnt i Al i as) and one
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 53

method (Get Pr evi ewPageI nf o). The UseAnt i Al i as property indicates whether
anti-aliasing will be used when the print preview is being displayed.

The Get Pr evi ewPageI nf o method captures the pages of a document as a series of
images and returns them as an array called Pr evi ewPageI nf o. The
Pr evi ewPageI nf o class provides print preview information for a single page. This
class has two properties: I mage and Physi cal Si ze. The I mage property returns an
Image object, which represents an image of the printed page, and Physi cal Si ze
represents the size of the printed page in hundredths of an inch.

Lets write a sample application. We create a Windows application, and we add a
Mai nMenu control, and item and a St at usBar control to the form. Our final form
looks like Figure 22.



Figure 22: Print controller test form

Before adding any code to this form, we create a MyPr i nt cont r ol l er class, which is
inherited from St andar dPr i nt Cont r ol l er . You can use the
Pr evi ewPr i nt Cont r ol l er or Pr i nt Cont r ol l er Wi t hSt at usDi al og
classes in the same way. The code for the MyPr i nt Cont r ol l er class is given in
Listing 42. We override all four methods: OnSt ar t Pr i nt , OnSt ar t Page,
OnEndPr i nt , and OnEndPage. On these methods we notify the status bar about the
status of the printing process. This information could be useful for displaying page
numbers or other print status information when were printing multipage documents.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 54

Listing 42: The MyPrintController class

/ / Pr i nt cont r ol l er cl ass
cl ass MyPr i nt Cont r ol l er : St andar dPr i nt Cont r ol l er
{
pr i vat e St at usBar st at usBar ;
pr i vat e st r i ng st r = st r i ng. Empt y;
publ i c MyPr i nt Cont r ol l er ( St at usBar sBar ) : base( )
{
st at usBar = sBar ;
}
publ i c over r i de voi d OnSt ar t Pr i nt ( Pr i nt Document pr i nt Doc,
Pr i nt Event Ar gs peAr gs)
{
st at usBar . Text = " OnSt ar t Pr i nt Cal l ed" ;
base. OnSt ar t Pr i nt ( pr i nt Doc, peAr gs) ;
}
publ i c over r i de Gr aphi cs OnSt ar t Page( Pr i nt Document pr i nt Doc,
Pr i nt PageEvent Ar gs ppea)
{
st at usBar . Text =" OnSt ar t PAget Cal l ed" ;
r et ur n base. OnSt ar t Page ( pr i nt Doc, ppea) ;
}
publ i c over r i de voi d OnEndPage( Pr i nt Document pr i nt Doc,
Pr i nt PageEvent Ar gs ppeAr gs)
{
st at usBar . Text = " OnEndPage Cal l ed" ;
base. OnEndPage ( pr i nt Doc, ppeAr gs) ;
}
publ i c over r i de voi d OnEndPr i nt ( Pr i nt Document pr i nt Doc,
Pr i nt Event Ar gs peAr gs)
{
st at usBar . Text = " OnEndPr i nt Cal l ed" ;
st at usBar . Text = st r ;
base. OnEndPr i nt ( pr i nt Doc, peAr gs) ;
}
}

To call the MyPr i nt Cont r ol l er class, we need to set the Pr i nt Cont r ol l er
property of Pr i nt Document to invoke MyPr i nt Cont r ol l er s overridden
methods. Lets write a menu click event handler and set the create a Pr i nt Document
object, set its Document Name and Pr i nt Cont r ol l er properties, enable the
Pr i nt Page event handler, and call Pr i nt to print the document.

Listing 43: Setting the PrintController property of PrintDocument

pr i vat e voi d St andar dPr i nt Cont r ol l er Menu_Cl i ck (
obj ect sender , Syst em. Event Ar gs e)
{
Pr i nt Document pr i nt Doc = new Pr i nt Document ( ) ;
pr i nt Doc. Document Name =" Pr i nt Cont r ol l er Document " ;
pr i nt Doc. Pr i nt Cont r ol l er =new MyPr i nt Cont r ol l er ( st at usBar 1) ;
pr i nt Doc. Pr i nt Page +=new Pr i nt PageEvent Handl er ( Pr i nt PageHandl er ) ;
pr i nt Doc. Pr i nt ( ) ;
}
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 55


Listing 44 gives the code for the Pr i nt Page event handler which, just draws some text
on the printer.

Listing 44: The PrintPage event handler

voi d Pr i nt PageHandl er ( obj ect obj , Pr i nt PageEvent Ar gs ppeAr gs)
{
Gr aphi cs g = ppeAr gs. Gr aphi cs;
Sol i dBr ush br ush = new Sol i dBr ush ( Col or . Red) ;
Font ver dana20Font = new Font ( " Ver dana" , 20) ;
g. Dr awSt r i ng ( " Pr i nt Cont r ol l er Test " , ver dana20Font , br ush, 20,
20) ;
}



Figure 23: Print controller output

If we run the application and print, we will see that the status bar displays the status of
the printing process. The first event message is shown in Figure 23.

You can extend this functionality to write your own custom print controllers.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 56

Printing a Form



Figure 24: Printing a Form in .NET

Printing a Form is easily accomplished using the DrawToBitmap method provided
with the .NET 2.0 Framework. The code in listing 45 can be placed inside the
PrintPage event handler to print out an existing snapshot of your form. This code
simply draws the entire form to a bitmap that is the same size as the form on your screen.
The bitmap is then drawn to the printing surface using the DrawImage method.

Listing 45: Printing a Form through a Bitmap of the Form

pr i vat e voi d pr i nt Document 1_Pr i nt Page( obj ect sender ,
Syst em. Dr awi ng. Pr i nt i ng. Pr i nt PageEvent Ar gs e)
{
/ / cr eat e a bi t map t he si ze of t he f or m
Bi t map bmp = new Bi t map( t hi s. Wi dt h, t hi s. Hei ght ) ;

/ / dr aw t he f or mi mage t o t he bi t map
Dr awToBi t map( bmp, new Rect angl e( 0, 0, Wi dt h, Hei ght ) ) ;

/ / dr aw t he bi t map i mage of t he
/ / f or mont o t he gr aphi cs sur f ace
e. Gr aphi cs. Dr awI mage( bmp, new Poi nt ( 0, 0) ) ;
}

If you want to activate the PrintPage event handler of the PrintDocument, just use
the code in Listing 46. The code will call the PrintDocuments Print method if the
setup dialog was successfully Okayed.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 57


Listing 46: Activating the PrintPage Event Handler to Print the Form

pr i vat e voi d pr i nt Tool St r i pMenuI t em_Cl i ck( obj ect sender ,
Event Ar gs e)
{
i f ( pr i nt Di al og1. ShowDi al og( ) == Di al ogResul t . OK)
{
pr i nt Document 1. Pr i nt ( ) ;
}
}

Printing the DataGridView Control

The DataGridView is printed by brute force. We need to draw all the grid lines, text,
pictures, and controls directly to the graphics surface. We obtain the contents of the grid
directly through the DataSet bound to the grid. Listing 47 kicks off the drawing of the
Dat aGr i dVi ew through the Pr i nt Page event handler.

Listing 47: Printing a DataGridView

pr i vat e voi d pr i nt Document 1_Pr i nt Page( obj ect sender ,
Syst em. Dr awi ng. Pr i nt i ng. Pr i nt PageEvent Ar gs e)
{
Font bol dFont = new Font ( t hi s. Font , Font St yl e. Bol d) ;
Gr aphi cs g = e. Gr aphi cs;
Dr awDat aGr i dVi ew( bol dFont , g, e) ;
}

pr i vat e voi d Dr awDat aGr i dVi ew( Font bol dFont , Gr aphi cs g,
Pr i nt PageEvent Ar gs e)
{

/ / Pr i nt t he dat a and t i me
i nt col umnPosi t i on = 0;
i nt r owPosi t i on = 25;
g. Dr awSt r i ng( dat eTi mePi cker 1. Val ue. ToSt r i ng( ) , t hi s. Font ,
Br ushes. Bl ack, 0, 0) ;

/ / dr aw header s
Dr awHeader ( bol dFont , g, r ef col umnPosi t i on, r ef r owPosi t i on) ;

r owPosi t i on += 65;
i nt hei ght = e. PageBounds. Hei ght ;

/ / dr aw each r ow
Dr awGr i dBody( g, r ef col umnPosi t i on, r ef r owPosi t i on, e) ;
}

In order to print the contents of the Dat aGr i dVi ew control, well need to cycle through
each row of the DataSet bound to the grid. Then we go through each
Dat aGr i dVi ewCol umn and determine the value of the DataPropertyName or the
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 58

ValueType. If the ValueType is a Boolean, well literally draw the checkbox to
the graphics surface using Dr awSt r i ng. If the ValueType is a String, well draw
a string to the graphics surface using Dr awRect angl e. To get the value of the string
we can use the Dat aPr oper t yName of the Dat aGr i dVi ewCol umn to reference the
Dat aRow s value at the column in which we are interested. For example, to get the
value at a particular column of the instance of the Dat aRow called dr, we could obtain
its instance through dr [ dat aCol umn. Dat aPr oper t yName]. Listing 48 draws the
body of the grid to our printing graphics surface. Note that printing a picture in the
Dat aGr i dVi ew is handled by using the Dr awI mage method of the Gr aphi cs
object.

Listing 48: Drawing the Body of the DataGridView

pr i vat e i nt _l ast Row = 0;
pr i vat e voi d Dr awGr i dBody( Gr aphi cs g, r ef i nt col umnPosi t i on, r ef i nt
r owPosi t i on, Pr i nt PageEvent Ar gs e)
{
/ / l oop t hr ough each r ow and dr aw t he dat a t o t he gr aphi cs
/ / sur f ace.
Dat aSet ds = ( Dat aSet ) ( ( Bi ndi ngSour ce) gr i dExer ci se. Dat aSour ce) .
Dat aSour ce;
f or ( i nt count = _l ast Row; count < ds. Tabl es[ 0] . Rows. Count ;
count ++)
{
Dat aRow dr = ds. Tabl es[ 0] . Rows[ count ] ;
col umnPosi t i on = 0;

/ / dr aw a l i ne t o separ at e t he r ows

g. Dr awLi ne( Pens. Bl ack, new Poi nt ( 0, r owPosi t i on) , new
Poi nt ( t hi s. Wi dt h, r owPosi t i on) ) ;

/ / l oop t hr ough each col umn i n t he r ow, and
/ / dr aw t he i ndi vi dual dat a i t em
f or each ( Dat aGr i dVi ewCol umn dc i n gr i dExer ci se. Col umns)
{
/ / i f i t s a pi ct ur e, dr aw a bi t map
i f ( dc. Dat aPr oper t yName == " Pi ct ur e" )
{
i f ( dr [ dc. Dat aPr oper t yName] . ToSt r i ng( ) . Lengt h
! = 0)
{
i f ( Cust omI mageCel l . I mages. Cont ai nsKey(
dr [ dc. Dat aPr oper t yName] . ToSt r i ng( ) ) )
{
g. Dr awI mage( Cust omI mageCel l . I mages[
dr [ dc. Dat aPr oper t yName] . ToSt r i ng( ) ] , new Poi nt ( col umnPosi t i on,
r owPosi t i on) ) ;
}
}
}
el se i f ( dc. Val ueType == t ypeof ( bool ) )
{
/ / dr aw a check box i n t he col umn
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 59

g. Dr awRect angl e( Pens. Bl ack, new Rect angl e(
col umnPosi t i on, r owPosi t i on + 20, 10, 10) ) ;
}
el se
{
/ / j ust dr aw st r i ng i n t he col umn
st r i ng t ext =dr [ dc. Dat aPr oper t yName] . ToSt r i ng( ) ;
i f ( dc. Def aul t Cel l St yl e. Font ! = nul l )
g. Dr awSt r i ng( t ext , dc. Def aul t Cel l St yl e. Font , Br ushes. Bl ack,
( f l oat ) col umnPosi t i on, ( f l oat ) r owPosi t i on + 20f ) ;
el se
g. Dr awSt r i ng( t ext , t hi s. Font , Br ushes. Bl ack,
( f l oat ) col umnPosi t i on, ( f l oat ) r owPosi t i on + 20f ) ;

}

/ / go t o t he next col umn posi t i on
col umnPosi t i on += dc. Wi dt h + 5;
}

/ / go t o t he next r ow posi t i on
r owPosi t i on = r owPosi t i on + 65;

/ / i f t he r ow Posi t i on i s gr eat er t han t he si ze
/ / of t he page ( mi nus t he bot t ommar gi n)
/ / r et ur n so we pr i nt t o t he next page
i f ( r owPosi t i on > e. PageBounds. Hei ght - 65)
{
_l ast Row = count +1;
e. HasMor ePages = t r ue;
r et ur n;
}
}
}

Drawing the header is accomplished in much the same way as drawing the body of the
DataGridView. You simply go through each column of the DataGridView and
pick out the header text. Then draw the header text to the graphics surface using
DrawString. The next position of the text in the header is determined by the
accumulated sum of all the previous column widths as shown in listing 49.

Listing 49: Drawing the Header of the DataGridView

pr i vat e i nt Dr awHeader ( Font bol dFont , Gr aphi cs g,
r ef i nt col umnPosi t i on, r ef i nt r owPosi t i on)
{
f or each ( Dat aGr i dVi ewCol umn dc i n gr i dExer ci se. Col umns)
{
g. Dr awSt r i ng( dc. Header Text , bol dFont , Br ushes. Bl ack,
( f l oat ) col umnPosi t i on, ( f l oat ) r owPosi t i on) ;
col umnPosi t i on += dc. Wi dt h + 5;
}
r et ur n col umnPosi t i on;
}
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 60

Printing an Invoice



Figure 25: The Invoice in a Windows Form

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 61

This program could be improved but it will allow you to create and print invoices. You
can customize the invoice by changing the bitmap supplied in the download to an invoice
of your choice and then moving the controls to fit into the proper locations on the
background bitmap. This invoice layout was scanned from a standard invoice form and
modified to add a few features.

Below is the design for the InvoiceMaker.NET program in UML:



Figure 26: UML Diagram of InvoiceMaker.NET

The program has several useful pieces of code. Printing the invoice is accomplished
through the following steps: a) draw the empty form bitmap to the graphics surface, b)
loop through each control in the form, and c) individually draw the control to the graphics
surface. It is also important to position each control correctly to the graphics surface so
that they all align with the empty form bitmap. The position of each control is scaled to a
printed page so they all line up properly.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 62

Each type of control is handled separately in order to draw its specific internal shapes.
There are three types of controls in our invoice: a TextBox, a CheckBox, and a
ListView control.

Printing the TextBox is accomplished by drawing a rectangle border to the graphics
surface with text inside. Printing a CheckBox is accomplished by drawing a square to
the graphics surface with or without an x, depending upon the state of the CheckBox.
Printing the ListView is a bit more complex. The code for printing the ListView
simply cycles through the ListView Items and through each ListView Item's
Subitem and prints them to the graphics surface using DrawString. The horizontal
position of the string is determined using the widths in the Columns collection of the
ListView. Note that the position is scaled to the printing surface.

Listing 50: Drawing the Invoice to the Print Graphics surface

pr i vat e voi d Dr awTheI nvoi ce( Gr aphi cs g)
{
/ / Cr eat e t he sour ce r ect angl e f r omt he Backgr oundI mage Bi t map
/ / Di mensi ons
Rect angl eF sr cRect = new Rect angl e( 0, 0,
t hi s. Backgr oundI mage. Wi dt h, Backgr oundI mage. Hei ght ) ;
/ / Cr eat e t he dest i nat i on r ect angl e f r omt he pr i nt er set t i ngs
/ / hol di ng pr i nt er page di mensi ons
i nt nWi dt h =
pr i nt Document 1. Pr i nt er Set t i ngs. Def aul t PageSet t i ngs. Paper Si ze. Wi dt h;
i nt nHei ght =
pr i nt Document 1. Pr i nt er Set t i ngs. Def aul t PageSet t i ngs. Paper Si ze. Hei ght ;
Rect angl eF dest Rect = new Rect angl e( 0, 0, nWi dt h, nHei ght / 2) ;
/ / Dr aw t he empt y f or mi mage scal ed t o f i t on a pr i nt ed page
g. Dr awI mage( t hi s. Backgr oundI mage, dest Rect , sr cRect ,
Gr aphi csUni t . Pi xel ) ;
/ / Det er mi ne t he scal i ng f act or s of each di mensi on based on t he
/ / bi t map and t he pr i nt ed page di mensi ons
/ / These f act or s wi l l be used t o scal e t he posi t i oni ng of t he
/ / cont r o cont ent s on t he pr i nt ed f or m
f l oat scal ex = dest Rect . Wi dt h/ sr cRect . Wi dt h;
f l oat scal ey = dest Rect . Hei ght / sr cRect . Hei ght ;
Pen aPen = new Pen( Br ushes. Bl ack, 1) ;
/ / Cycl e t hr ough each cont r ol . Det er mi ne i f i t ' s a checkbox or a
/ / t ext box and dr aw t he i nf or mat i on i nsi de
/ / i n t he cor r ect posi t i on on t he f or m
f or ( i nt i = 0; i < t hi s. Cont r ol s. Count ; i ++)
{
/ / Check i f i t s a Text Box t ype by compar i ng t o t he t ype of one of
/ / t he t ext boxes
i f ( Cont r ol s[ i ] . Get Type( ) == t hi s. Wages. Get Type( ) )
{
/ / Unbox t he Text box
Text Box t heText = ( Text Box) Cont r ol s[ i ] ;
/ / Dr aw t he t ext box st r i ng at t he posi t i on of t he t ext box
/ / on t he
/ / f or m, scal ed t o t he pr i nt page
g. Dr awSt r i ng( t heText . Text , t heText . Font , Br ushes. Bl ack,
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 63

t heText . Bounds. Lef t *scal ex, t heText . Bounds. Top * scal ey, new
St r i ngFor mat ( ) ) ;
}
i f ( Cont r ol s[ i ] . Get Type( ) ==
t hi s. Ret i r ement Pl anCheck. Get Type( ) )
{
/ / Unbox t he Checkbox
CheckBox t heCheck = ( CheckBox) Cont r ol s[ i ] ;
/ / Dr aw t he checkbox r ect angl e on t he f or mscal ed t o
/ / t he pr i nt page
Rect angl e aRect = t heCheck. Bounds;
g. Dr awRect angl e( aPen, aRect . Lef t *scal ex,
aRect . Top*scal ey, aRect . Wi dt h*scal ex, aRect . Hei ght *scal ey) ;
/ / I f t he checkbox i s checked, Dr aw t he x i nsi de t he checkbox on
/ / t he f or mscal ed t o t he pr i nt page
i f ( t heCheck. Checked)
{
g. Dr awSt r i ng( " x" , t heCheck. Font ,
Br ushes. Bl ack, t heCheck. Lef t *scal ex + 1, t heCheck. Top*scal ey + 1, new
St r i ngFor mat ( ) ) ;
}
}
}
/ / handl e Li st Vi ew Cont r ol pr i nt i ng
i f ( Cont r ol s[ i ] . Get Type( ) == t hi s. l i st Vi ew1. Get Type( ) )
{
f or ( i nt r ow = 0; r ow < l i st Vi ew1. I t ems. Count ; r ow++)
{
i nt next Col umnPosi t i on = l i st Vi ew1. Bounds. X;
f or ( i nt col = 0; col < l i st Vi ew1. I t ems[ r ow] . SubI t ems. Count ;
col ++)
{
g. Dr awSt r i ng( l i st Vi ew1. I t ems[ r ow] . SubI t ems[ col ] . Text ,
l i st Vi ew1. I t ems[ r ow] . Font , Br ushes. Bl ack, ( next Col umnPosi t i on +
3) *scal ex, ( l i st Vi ew1. I t ems[ r ow] . Bounds. Y +
l i st Vi ew1. Bounds. Y) * scal ey, new St r i ngFor mat ( ) ) ;
next Col umnPosi t i on += l i st Vi ew1. Col umns[ col ] . Wi dt h;
}
}
}

Printing a Ruler

If you misplaced your ruler, here's an application that will create one for you on your
printer! You will still need a ruler when you begin so that you can calibrate the
measurement for your particular printer. Fortunately, once you know the calibration
value, you are all set with a fairly accurate ruler. Below is the simple design of our ruler.
The ruler itself is drawn in a Form. The only other class used is the calibration dialog
used to enter and retrieve a calibration value:
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 64



Figure 27: Part of the ruler
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 65



Figure 28: UML Diagram of Ruler

The ruler is created by simply determining the resolution in pixels per inch. This
information can be retrieved from the graphics object itself:

Listing 51: Getting the Pixels per Inch of the Ruler

voi d Si zeFor mToRul er ( )
{
/ / get r esol ut i on, most scr eens ar e 96 dpi , but you never know. . .
Gr aphi cs g = t hi s. Cr eat eGr aphi cs( ) ;
t hi s. HRes = g. Dpi X;
t hi s. VRes = g. Dpi Y;
Wi dt h = Syst em. Conver t . ToI nt 32( HRes) ;
Hei ght = Syst em. Conver t . ToI nt 32( VRes) * 11;
Lef t = 250;
Top = 5;
}

The actual tick marks and numbers are drawn in the Form_Paint event handler
method. This method establishes a ruler height in inches and then calls the method
DrawRuler to draw the ruler:

Listing 52: Drawing the Ruler in the Paint Event Handler

pr i vat e voi d For m1_Pai nt ( obj ect sender ,
Syst em. Wi ndows. For ms. Pai nt Event Ar gs e)
{
Gr aphi cs g = e. Gr aphi cs;
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 66

Rul er Hei ght = 11;
Dr awRul er ( g) ;
}

The DrawRuler method is the heart of the application. It draws the tick marks and
numbers and then spaces them according to the number of pixels in an inch (+a
calibration value to make the inch measurement accurate). The modulus function is used
to determine when it is appropriate to draw a particular tick mark. For example when
(i mod PixelsPerInch) is equal to zero, then we've found an inch marker.

Listing 53: Drawing the Ruler on the Graphics Surface

pr i vat e voi d Dr awRul er ( Gr aphi cs g)
{
g. Dr awRect angl e( Pens. Bl ack, Cl i ent Rect angl e) ;
g. Fi l l Rect angl e( Br ushes. Whi t e, 0, 0, Wi dt h, Hei ght ) ;

f l oat Pi xel sPer I nch = ( f l oat ) ( VRes +
Syst em. Conver t . ToSi ngl e( Cal i br at i on) ) ;

i nt count = 1;
f l oat i = 0F;
f or ( i = 1; i <= ( Syst em. Conver t . ToSi ngl e( Pi xel sPer I nch) *
Rul er Hei ght + 10) - 0. 0625F; i += 0. 0625F) / / mar k ever y 1/ 8t h i nch
{
i f ( i %Pi xel sPer I nch == 0)
{
g. Dr awLi ne( Pens. Bl ack, 0, i , 25, i ) ;
g. Dr awSt r i ng( count . ToSt r i ng( ) , TheFont , Br ushes. Bl ack, 25F,
i , new St r i ngFor mat ( ) ) ;
count += 1;
}
el se
{
i f ( i * 2 %Pi xel sPer I nch == 0)
{
g. Dr awLi ne( Pens. Bl ack, 0, i , 20, i ) ;
}
el se
{
i f ( i * 4 %Pi xel sPer I nch == 0)
{
g. Dr awLi ne( Pens. Bl ack, 0, i , 15, i ) ;
}
el se
{
i f ( i * 8 %Pi xel sPer I nch == 0)
{
g. Dr awLi ne( Pens. Bl ack, 0, i , 10, i ) ;
}
el se
{
i f ( i * 16 %Pi xel sPer I nch == 0)
{
g. Dr awLi ne( Pens. Bl ack, 0, i , 5, i ) ;
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 67

}
}
}
}
}
}
}

The calibration value is retrieved by using the calibration dialog. This dialog brings up a
NumericUpDown control for choosing the number of pixels to offset the inch. The offset
can be a negative or positive number of pixels depending upon how much your printer is
off. I found that my printer was 4 pixels too short, so my calibration was +4. Below is
the calibration dialog:



Figure 29: Ruler Calibration Dialog

The calibration dialog uses ShowDialog to display the form and retrieves the
calibration value in the CalibrationValue property of the dialog:

Listing 54: Entering a Calibration Value for the Ruler

pr i vat e voi d Cal i br at i onMenu_Cl i ck( obj ect sender , Syst em. Event Ar gs e)
{
Cal i br at i onFor mCal i br For m= new Cal i br at i onFor m( ) ;
Cal i br For m. Cal i br at i onVal ue = Cal i br at i on;
i f ( Cal i br For m. ShowDi al og( ) ==
Syst em. Wi ndows. For ms. Di al ogResul t . OK)
{
Cal i br at i on = Cal i br For m. Cal i br at i onVal ue;
Wr i t eCal i br at i on( ) ;
}
I nval i dat e( ) ;
}

Printing the ruler is accomplished using three different print controls: The
PrintDocument, The PrintDialog, and the PrintPreviewDialog control.
Once you've dropped these controls on your form and assigned the PrintDocument
instance to the corresponding Document properties in the PrintDialog and the
PrintPreviewDialog, it's fairly easy to set up printing. Below is the event handler
for the Print Preview menu item. As you can see, there is not really much to it.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 68

Listing 55: Executing Print Preview Dialog

pr i vat e voi d Pr i nt Pr evi ewMenu_Cl i ck( obj ect sender , Syst em. Event Ar gs e)
{
t hi s. pr i nt Pr evi ewDi al og1. ShowDi al og( ) ;
}

Printing is not much more complicated. Simply open the PrintDialog and once the
user has assigned properties, call the Print method on the PrintDocument:

Listing 56: Executing Printing for the Ruler

pr i vat e voi d Pr i nt Menu_Cl i ck( obj ect sender , Syst em. Event Ar gs e)
{
i f ( pr i nt Di al og1. ShowDi al og( ) ==
Syst em. Wi ndows. For ms. Di al ogResul t . OK)
{
pr i nt Document 1. Pr i nt ( ) ;
}
}

The actual printing occurs in the PrintDocument's PrintPage Event Handler. This is
where you put all the GDI routines for drawing the ruler. You can actually use the same
drawing routines in your print handler as you do for your Paint Handler. Youre just
passing in a printer graphics object instead of a screen graphics object:

Listing 57: The Print Event Handler for Printing the Ruler

pr i vat e voi d pr i nt Document 1_Pr i nt Page( obj ect sender ,
Syst em. Dr awi ng. Pr i nt i ng. Pr i nt PageEvent Ar gs e)
{
Gr aphi cs g = e. Gr aphi cs;
PageSet t i ngs ps = e. PageSet t i ngs;
Rul er Hei ght = Syst em. Conver t . ToI nt 32( ps. Bounds. Hei ght / 100. 0) ;
Dr awRul er ( g) ;
}

We've also added persistence to this application to remember the calibration value. The
two routines below read and write the calibration value using the StreamReader and
StreamWriter classes:

Listing 58: Reading the Calibration Value of the Ruler from a File

voi d ReadCal i br at i on( )
{
/ / Det er mi ne t he pat h of t he f i l e f r omt he appl i cat i on i t sel f
st r i ng cal f i l e = Appl i cat i on. St ar t upPat h + " \ \ cal . t xt " ;
/ / I f t he cal i br at i on f i l e exi st s, r ead i n t he i ni t i al cal i br at i on
val ue
i f ( Fi l e. Exi st s( cal f i l e) )
{
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 69

St r eamReader t r = new St r eamReader ( cal f i l e) ;
st r i ng num= t r . ReadLi ne( ) ;
Cal i br at i on = Conver t . ToI nt 32( num) ;
t r . Cl ose( ) ;
}
}

Listing 59: Writing out a Calibration Value for the Ruler to a File

voi d Wr i t eCal i br at i on( )
{
st r i ng cal f i l e = Appl i cat i on. St ar t upPat h + " \ \ cal . t xt " ;
St r eamWr i t er st Wr i t er = new St r eamWr i t er ( cal f i l e) ;
st Wr i t er . Fl ush( ) ;
st Wr i t er . Wr i t eLi ne( Cal i br at i on. ToSt r i ng( ) ) ;
st Wr i t er . Cl ose( ) ;
}

Improvements

This control could be improved by adding a metric ruler option. This can be
accomplished simply by figuring out the pixels per centimeter and then using modulus 10
to get the millimeters. Also a large ruler can be created by printing to multiple pages.
I'm sure you can think of some other ideas with a little measured thought.

Bar Code Printing



Figure 30: Bar Code Printer Form for ISBN and Book Pricing for
Harry Potter and the Order of the Phoenix
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 70


Bar Codes are the way we label food, books, and other manufactured items to identify
them at the register. A bar code can contain information about the product and the price
of the product. EAN-13 is one of the standard bar code formats and it is used by
publishers to create ISBN numbers for books. In this article we will show you how to
generate and print an EAN-13 bar code.

Forming the EAN-13 Number

Before an ISBN number is encoded, you need to form a number to encode. A country
prefix is added to the ISBN. For books published in the USA, this number is 978. For
other countries this number will differ. The first nine numbers of the ISBN are used to
complete the code, and then a checksum is tagged on as the final number. For the
HarryPotter Book the EAN-13 number is encoded as:

Country Code + ISBN +Checksum

or 978 +043935806 +4

Understanding the EAN-13 Bar Code

Bar Codes are nothing more than binary numbers encoding a serial number for a book.
The black lines represent ones and the white lines represent zeroes. All EAN-13 bar
codes are made up of the following components:

Left Guard Bars - This is a 101, which means black line, white line, black line. The
height of the lines is extended to exaggerate the starting point.

Characters 2 through 7 (left side sequence) - These characters are encoded by a parity
system. The parity of each number at a particular position in the entire bar code
sequence is determined by character #1. Also, character #1 is implicitly encoded through
the type of parity used for every character in the bar code, so you don't need bars for
character #1. (Don't even begin to ask me why its done this way; I guess it saves you a
few bars for character #1.) There is a look-up table used by the program to determine
how Characters 2-7 are encoded based on both their position in the sequence and
character #1. Also note that characters on the left side always start with 0 (as a white
line). They are encoded differently from the right side.

Center Guard - encoded as 01010.

Characters 8 through 12 (right side sequence) - The right side sequence is a little more
straightforward and doesn't depend on positions or the first character. There is a one to
one binary number correspondence to a particular number. For example 2 is 1101100 on
the right side. All right side characters start with a binary 1 (as a black line).

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 71

Character 13 (The CheckSum) - This character is computed by summing all of the
alternating positions of the 12 digit number (numbers at position 1,3,5,7,9,11) and
adding a 3X weighted sum of the rest of the numbers (at positions 2,4,6,8,12). The least
significant digit of this sum is taken and subtracted from 10. If the answer is 10 then we
use 0 as the checksum. (See Bar Code Island for an example of this calculation.)
Right Guard - Same as the Left Guard, 101.

Supplemental 5-digit Price Code

This is handled much differently from the EAN-13 number. First of all, the number
prefixed on the front of the bar code represents the currency. The dollar currency (USD)
is represented by a 5. There is no decimal character in the numeric representation but it is
assumed before the last 2 numbers. For example, a book priced at $29.99 would be
represented as 52999.

Supplemental Bar Code

1. First, a checksum is computed and used to determine parity for bar coding. The
checksum is determined by adding numbers at positions (1,3,5) and multiplying by 3.
Then numbers are taken at positions (2 and 4) and multiplied by 9. Then these
numbers are added together and the least significant digit is taken.
2. Left Guard - 1011 or black line, white line, thick black line (2 black lines
together)
3. Characters 1-5, encoded using the appropriate parity pattern based on the checksum
and separated by 01

Bar Code Printing Application

The Bar Code Printing application was written in C#and allows you to print or print
preview the bar code as well as save the bar code to a bitmap. You can't print a series of
bar code labels on a sheet of paper, but .NET will allow you to convert the application
over.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 72

Below is the simple UML design of the Bar CodePrinter:



Figure 31: UML Design of Bar Code Printer reverse engineered from C# using
WithClass

This could probably be broken out into 3 more classes: Bar CodeCalculator,
EAN13Calculator, and SupplementalCalculator. However, in this article all
the methods for calculation are contained in the form: CalculateISBNBar Code
and CalculatePriceBar Code. CalculateISBNBar Code is shown below.
Note that it follows the steps we described at the beginning of this article:

Listing 60: Calculating the EAN-13 number in C#

pr i vat e st r i ng Cal cul at eI SBNBar Code( )
{

t r y
{
_i sbn = t hi s. I SBNText Box. Text . Tr i m( ) ;

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 73

/ / save t he or i gi nal
_Or i gi nal I SBN = _i sbn;
/ / add U. S. count r y code
_i sbn = " 978" + RemoveUnwant edChar act er s( _i sbn) ;
/ / l ef t guar d i s " 101"
_bar code = " 101" ;

/ / f i r st number i s encoded by par i t y code
st r i ng f i r st Number = _i sbn[ 0] . ToSt r i ng( ) ;
i nt nFi r st Number = Conver t . ToI nt 32( f i r st Number ) ;
/ / f or ml ef t si de bi nar y st r i ng based on t he f i r st number
( 9 f or U. S. )
st r i ng l ef t Si deDat a = For mLef t Si deDat a( nFi r st Number ) ;
/ / add i t t o bar code
_bar code += l ef t Si deDat a;
/ / add cent er guar d
_bar code += " 01010" ;
/ / get r i ght si de dat a
st r i ng r i ght Si deDat a = For mRi ght Si deDat a( ) ;
/ / add r i ght si de dat a t o bar code
_bar code += r i ght Si deDat a;
/ / cal cul at e Checksumand add i t usi ng r i ght si de dat a
i nt checkSum= Cal cul at eCheckSum( ) ;
/ / l ast char act er of 13 di gi t s i s checksum
_i sbn = _i sbn. Subst r i ng( 0, 12) + Conver t . ToSt r i ng( checkSum) ;
/ / t ag on t he checksumt o t he end
_bar code += Bar CodeDat a[ checkSum, 2] ;
/ / add r i ght guar d
_bar code += " 101" ;
}
cat ch ( Except i on ex)
{
MessageBox. Show( ex. ToSt r i ng( ) ) ;
}
r et ur n _bar code;
}

Printing the Bar Code

Printing the bar code is accomplished in a routine called DrawBar Code which is
called from the PrintPage event handler. This drawing routine takes the final EAN-
13 bar code binary string and the Supplemental Price binary string and prints it out in its
bar code form with 1's represented by black lines and 0's represented by white lines. The
draw routine also adds the appropriate strings above and below the bar code graphics.

Listing 61: Drawing the Bar Code to the Printer

pr i vat e voi d Dr awBar Code( Gr aphi cs g)
{
/ / est abl i sh pai nt i ng r ect angl e
Rect angl e r = GOBut t on. Bounds;
Rect angl e I SBNBounds = new Rect angl e( r . Ri ght + 10, r . Top - 40, 200,
150) ;
g. Fi l l Rect angl e( Br ushes. Whi t e, I SBNBounds) ;
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 74

/ / set up posi t i ons of t he ext ended bar s i n t he EAN- 13 code
i nt [ ] LongPosi t i ons = new i nt [ ] {0, 1, 2, 3, 45, 46, 47, 48, 92, 93, 94,
95};
/ / set up t he t er mi nat i on posi t i ons of l ef t , cent er , and r i ght guar ds
i nt [ ] Ter mi nat i onPosi t i ons = new i nt [ ] {3, 48, 93};
/ / used t o adj ust ver t i cal l engt h of bar s
i nt adj ust ment = 25;
/ / St i ck EAN- 13 Bar Code i n Pai nt i ng Rect angl e
f or ( i nt i = 0; i < _bar code. Lengt h; i ++)
{
/ / see i f t he posi t i on needs t o be l engt hened
i f ( Ar r ay. Bi nar ySear ch( LongPosi t i ons, 0, LongPosi t i ons. Lengt h, i ) >=
0)
adj ust ment = 25;
el se
adj ust ment = 35;
/ / dr aw a ver t i cal bl ack l i ne f or 1' s and
/ / a ver t i cal whi t e l i ne f or 0' s
i f ( _bar code[ i ] == ' 1' )
g. Dr awLi ne( Bl ackPen, I SBNBounds. Lef t + 10 + i ,
I SBNBounds. Top + 30,
I SBNBounds. Lef t + 10 + i ,
I SBNBounds. Bot t om- adj ust ment ) ;
el se
g. Dr awLi ne( Whi t ePen, I SBNBounds. Lef t + 10 + i ,
I SBNBounds. Top + 30,
I SBNBounds. Lef t + 10 + i ,
I SBNBounds. Bot t om- adj ust ment ) ;
}

/ / St i ck suppl ement al Bar Code i n Pai nt i ng Rect angl e
f or ( i nt i = 0; i < _pr i ceBar Code. Lengt h; i ++)
{
/ / dr aw a ver t i cal bl ack l i ne f or 1' s and
/ / a ver t i cal whi t e l i ne f or 0' s
i f ( _pr i ceBar Code[ i ] == ' 1' )
g. Dr awLi ne( Bl ackPen, I SBNBounds. Lef t + kPr i cePosi t i on + i ,
I SBNBounds. Top + 30,
I SBNBounds. Lef t + kPr i cePosi t i on + i ,
I SBNBounds. Bot t om- 30) ;
el se
g. Dr awLi ne( Whi t ePen, I SBNBounds. Lef t + kPr i cePosi t i on + i ,
I SBNBounds. Top + 30,
I SBNBounds. Lef t + kPr i cePosi t i on + i ,
I SBNBounds. Bot t om- 30) ;
}
i f ( t hi s. I SBNText Box. Text . Lengt h > 0)
{
/ / wr i t e out number s on t op and bot t omof t he bar code gr aphi c

/ / f i r st wr i t e out I SBN
g. Dr awSt r i ng( " I SBN " + _Or i gi nal I SBN, t hi s. Font , Br ushes. Bl ack,
I SBNBounds. Lef t + 10, I SBNBounds. Top + 17) ;
/ / al so wr i t e out t he code i n asci i
g. Dr awSt r i ng( _i sbn[ 0] . ToSt r i ng( ) , t hi s. Font , Br ushes. Bl ack,
I SBNBounds. Lef t , I SBNBounds. Bot t om- 32) ;
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 75

g. Dr awSt r i ng( _i sbn. Subst r i ng( 1, 6) , t hi s. Font , Br ushes. Bl ack,
I SBNBounds. Lef t + Ter mi nat i onPosi t i ons[ 0] + 10,
I SBNBounds. Bot t om- 32) ;
g. Dr awSt r i ng( _i sbn. Subst r i ng( 7, 6) , t hi s. Font , Br ushes. Bl ack,
I SBNBounds. Lef t + Ter mi nat i onPosi t i ons[ 1] + 10,
I SBNBounds. Bot t om- 32) ;
/ / al so wr i t e out pr i ce i n asci i
g. Dr awSt r i ng( _pr i ce + " >" , t hi s. Font , Br ushes. Bl ack,
I SBNBounds. Lef t + kPr i cePosi t i on, I SBNBounds. Top + 17) ;
}
}

Saving the Bar Code to a Bitmap

It is useful to know how to save an image to a bitmap. Basically, we just rework the
DrawBar Code method to draw to a bitmap rather than to the printer. Specifically, a
Graphics object is created from a bitmap and then sent to the DrawBar Code
method. Once the bitmap is drawn to, it is saved using the Save method of the Bitmap
class.

Listing 62: Saving the Bar Code to a Bitmap

/ / Cr eat e a Bl ank Bi t map
I mage i mage = new Bi t map( Cl i ent Rect angl e. Wi dt h,
Cl i ent Rect angl e. Hei ght ) ;
/ / Get a dr awi ng sur f ace f r omt he Bi t map
Gr aphi cs g = Gr aphi cs. Fr omI mage( i mage) ;
g. Smoot hi ngMode = Smoot hi ngMode. Hi ghQual i t y;

/ / Dr aw t he I mage t o t he Bi t map
Dr awBar Code( g) ;

/ / Save t he f i nal dr awn bi t map t o a f i l e.
i mage. Save( saveFi l eDi al og1. Fi l eName, I mageFor mat . Bmp) ;

Well it is that time of the year again. Time to get in shape for the summer months, and
what better way to do it then through a rigid exercise program. I was never very good at
tracking my progress in the gym, but thanks to .NET (and my wife), I have a way to do
just that. This program uses the DataGridView bound to a Microsoft Access Database to
create a printed sheet with your latest work out plans. The workout chart includes the
exercise, number of sets, number of reps, amount of weight, and most importantly,
whether or not you completed the exercise. The best part of this program is that you can
print out your exercise program and bring it with you to the weight room.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 76



Figure 32: Exercise Program

New Form Capture Feature

. NET comes with a new form capture feature: the ability to copy the form as you see it
on the screen into a bitmap. Although not useful for controls that you need to scroll, New
Form Capture Feature works if you can fit all the contents you need to see on the screen
into a bitmap. In this application, we stretched the DataGridView to allow for the full
contents of the exercises, and we enabled AutoScrolling on the Form. This way the
DataGridView will be much larger than the form, and the screen capture will print the
entire DataGridView contents to the printer. The exercise application gives you two
options: turning on the form capture feature to print out the form bitmap, or printing
using a customized DataGridView printing. The customized printing is the default mode
of the exercise program and it's more powerful because you can print the data in the grid
view beyond any scrolling limitations of the DataGridView. Below is the code for
capturing the form in a bitmap and drawing it to a graphics surface:

Listing 63: Printing the Form Capture to a Graphics Surface

pr i vat e voi d Dr awFor mSur f ace( Syst em. Dr awi ng. Pr i nt i ng. Pr i nt PageEvent Ar gs
e)
{
/ / cr eat e a bi t map t he si ze of t he f or m
Bi t map bmp = new Bi t map( gr i dExer ci se. Wi dt h, gr i dExer ci se. Hei ght ) ;
/ / dr aw t he f or mi mage t o t he bi t map
gr i dExer ci se. Dr awToBi t map( bmp, new Rect angl e( 0, 0,
gr i dExer ci se. Wi dt h, gr i dExer ci se. Hei ght ) ) ;
/ / dr aw t he bi t map i mage of t he f or mont o t he gr aphi cs sur f ace
e. Gr aphi cs. Dr awI mage( bmp, new Poi nt ( 0, 0) ) ;
}
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 77

Using a Filename to Map an Image in the DataGridView

We want to place an image of the exercise into the DataGridView without inserting the
image in the database. We prefer to place all the images in an images directory. Then we
will read the images file names from the database, retrieve the images from the images
directory, and put the images into the DataGridView. In order to accomplish all this, we'll
need to create a custom grid view column and grid view cell that inherits from
DataGridViewImageColumn and DataGridViewImageCell. We then override the
GetFormattedValue method in the custom DataGridViewImageCell class. In the
GetFormatted value method, we create a mapping between the file names and the actual
images. Below is the code for accomplishing the filename to image mapping in a
DataGridView:

Listing 64: Mapping Images into the DataGridView from file name Strings

usi ng Syst em;
usi ng Syst em. I O;
usi ng Syst em. Col l ect i ons. Gener i c;
usi ng Syst em. Text ;
usi ng Syst em. Dr awi ng;
usi ng Syst em. Wi ndows. For ms;
usi ng Syst em. Component Model ;
usi ng Syst em. Ref l ect i on;

namespace Exer ci sePr ogr am
{
/ / / <summar y>
/ / / Cr eat e a Cust omDat aGr i dVi ewI mageCol umn
/ / / </ summar y>
publ i c cl ass St r i ngI mageCol umn : Dat aGr i dVi ewI mageCol umn
{
publ i c St r i ngI mageCol umn( )
{
t hi s. Cel l Templ at e = new Cust omI mageCel l ( ) ;
t hi s. Val ueType = t ypeof ( st r i ng) ;
/ / val ue of t hi s col umn i s a st r i ng, but i t shows i mages i n t he cel l s
af t er f or mat t i ng
}
}

/ / / <summar y>
/ / / Cr eat e a Cust omDat aGr i dVi ewI mageCel l
/ / / </ summar y>
publ i c cl ass Cust omI mageCel l : Dat aGr i dVi ewI mageCel l
{
/ / mappi ng bet ween f i l ename and i mage
st at i c Syst em. Col l ect i ons. Gener i c. Di ct i onar y<st r i ng, I mage>
dot I mages = new Di ct i onar y<st r i ng, I mage>( ) ;
/ / l oad up cust omdot i mages
st at i c publ i c Syst em. Col l ect i ons. Gener i c. Di ct i onar y<st r i ng,
I mage> I mages
{
get
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 78

{
r et ur n dot I mages;
}
}
publ i c Cust omI mageCel l ( )
{
t hi s. Val ueType = t ypeof ( i nt ) ;
}
pr ot ect ed over r i de obj ect Get For mat t edVal ue(
obj ect val ue, i nt r owI ndex, r ef Dat aGr i dVi ewCel l St yl e cel l St yl e,
TypeConver t er val ueTypeConver t er , TypeConver t er
f or mat t edVal ueTypeConver t er , Dat aGr i dVi ewDat aEr r or Cont ext s cont ext )
{
i f ( val ue. Get Type( ) ! = t ypeof ( st r i ng) )
r et ur n nul l ;
/ / get t he i mage f r omt he st r i ng and r et ur n i t
LoadI mage( val ue) ;
/ / r et ur n t he mapped i mage
r et ur n dot I mages[ ( st r i ng) val ue] ;
}
publ i c st at i c voi d LoadI mage( obj ect val ue)
{
/ / l oad t he i mage f r omt he i mages di r ect or y i f i t does not exi st
i f ( dot I mages. Cont ai nsKey( ( st r i ng) val ue) == f al se)
{
st r i ng pat h = Pat h. Get Di r ect or yName
( Appl i cat i on. Execut abl ePat h) + " \ \ i mages\ \ " + ( st r i ng) val ue;
/ / r ead t he i mage f i l e
I mage t heI mage = I mage. Fr omFi l e( pat h) ;
/ / assi gn t he i mage mappi ng
dot I mages[ ( st r i ng) val ue] = t heI mage;
}
}
publ i c over r i de obj ect Def aul t NewRowVal ue
{
get
{
r et ur n 0;
}
}
}
}

Updating the Grid

The DataGridView is bound to the Microsoft Access Database via a DataGridAdapter.
We can edit the sets, reps, and weight values inside the grid while increasing body
strength and the program will persist these values to the database. Sometimes it is useful
to override the behavior of the DataGridView for updates and inserts in order to
customize how the grid is updated. Below is the ADO.NET code that updates the grid in
Microsoft Access without using the OleDb Adapter:

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 79

Listing 65: Updating the Microsoft Access Database after editing the GridView

/ / / <summar y>
/ / / Event Handl er cal l ed when Cel l i s f i ni shed edi t i ng
/ / / </ summar y>
/ / / <par amname=" sender " ></ par am>
/ / / <par amname=" e" ></ par am>
pr i vat e voi d gr i dExer ci se_Cel l EndEdi t ( obj ect sender ,
Dat aGr i dVi ewCel l Event Ar gs e)
{
Updat eCur r ent Row( e) ;
}
pr i vat e voi d Updat eCur r ent Row( Dat aGr i dVi ewCel l Event Ar gs e)
{
i nt i ndex = e. RowI ndex;
Dat aRow dr = schedul eDat aSet . Tabl es[ 0] . Rows[ e. RowI ndex] ;
st r i ng val =
dr [ gr i dExer ci se. Col umns[ e. Col umnI ndex] . Dat aPr oper t yName] . ToSt r i ng( ) ;
Ol eDbCommand updat eCommand = new Ol eDbCommand( ) ;
/ / const r uct updat e command and updat e f r omt he dat a set
updat eCommand. CommandText = " UPDATE `Schedul e` SET `Compl et ed` =
{0}, `Reps` = {1}, `Wei ght ` = {2}, `Set s` = {3} WHERE `I D` = {4}" ;
updat eCommand. CommandText = t r i ng. For mat ( updat eCommand. CommandText ,
dr [ " Compl et ed" ] , dr [ " Reps" ] , dr [ " Wei ght " ] , dr [ " Set s" ] , dr [ " I D" ] ) ;
updat eCommand. CommandType = Syst em. Dat a. CommandType. Text ;
updat eCommand. Connect i on = schedul eTabl eAdapt er . Connect i on;
updat eCommand. Connect i on. Connect i onSt r i ng = st r i ng. For mat (
@" Pr ovi der =Mi cr osof t . J et . OLEDB. 4. 0; Dat a Sour ce={0}\ Schedul e. mdb" ,
Pat h. Get Di r ect or yName( Appl i cat i on. Execut abl ePat h) ) ;
updat eCommand. Connect i on. Open( ) ;
/ / execut e t he updat e on t he dat abase
updat eCommand. Execut eNonQuer y( ) ;
updat eCommand. Connect i on. Cl ose( ) ;
}

Printing the DataGridView by Brute Force

Once we are satisfied with our exercise parameters, it is time to print out the exercise
schedule and head to the gym. Printing is accomplished using the PrintDocument in
conjuction with GDI+. Every row and column is painstakingly drawn to the print
graphics surface. Listing 66 shows the code that draws the exercise rows below the
header. The method loops through each row in the DataSet and draws the text
corresponding to the column in the data row. If the row contains a picture, rather than
text, the image that is mapped to the text in the cell is printed instead. We also need to
track the row and column position after placing each object onto the graphics surface so
we know where the next object goes. We do this by incrementing the local variables:
columnPosition and rowPosition.

Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 80

Listing 66: Printing out the Exercise Rows

pr i vat e voi d Dr awGr i dBody( Gr aphi cs g, r ef i nt col umnPosi t i on, r ef i nt
r owPosi t i on)
{
/ / l oop t hr ough each r ow and dr aw t he dat a t o t he gr aphi cs
/ / sur f ace.
f or each ( Dat aRow dr i n schedul eDat aSet . Tabl es[ 0] . Rows)
{
col umnPosi t i on = 0;

/ / dr aw a l i ne t o separ at e t he r ows
g. Dr awLi ne( Pens. Bl ack, new Poi nt ( 0, r owPosi t i on) , new
Poi nt ( t hi s. Wi dt h, r owPosi t i on) ) ;

/ / l oop t hr ough each col umn i n t he r ow, and
/ / dr aw t he i ndi vi dual dat a i t em
f or each ( Dat aGr i dVi ewCol umn dc i n gr i dExer ci se. Col umns)
{
/ / i f i t s a pi ct ur e, dr aw a bi t map
i f ( dc. Dat aPr oper t yName == " Pi ct ur e" )
{
i f ( dr [ dc. Dat aPr oper t yName] . ToSt r i ng( ) . Lengt h ! = 0)
{
i f ( Cust omI mageCel l . I mages. Cont ai nsKey
( dr [ dc. Dat aPr oper t yName] . ToSt r i ng( ) ) )
{
g. Dr awI mage( Cust omI mageCel l . I mages[ dr [ dc. Dat aPr oper t yName] . ToSt r i ng( ) ] ,
new Poi nt ( col umnPosi t i on, r owPosi t i on) ) ;
}
}
}
el se i f ( dc. Val ueType == t ypeof ( bool ) )
{
/ / dr aw a check box i n t he col umn
g. Dr awRect angl e( Pens. Bl ack, new
Rect angl e( col umnPosi t i on, r owPosi t i on + 20, 10, 10) ) ;
}
el se
{
i f ( dc. Def aul t Cel l St yl e. Font ! =
nul l ) g. Dr awSt r i ng( t ext , dc. Def aul t Cel l St yl e. Font ,
Br ushes. Bl ack, ( f l oat ) col umnPosi t i on, ( f l oat ) r owPosi t i on + 20f ) ;

el se
g. Dr awSt r i ng( t ext , t hi s. Font , Br ushes. Bl ack,
( f l oat ) col umnPosi t i on, ( f l oat ) r owPosi t i on + 20f ) ;
}

/ / go t o t he next col umn posi t i on
col umnPosi t i on += dc. Wi dt h + 5;
}
/ / go t o t he next r ow posi t i on
r owPosi t i on = r owPosi t i on + 65;
}
}
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 81

The DataGridView is even more full featured than the DataGrid and provides a good
interface for manipulating DataSets. This article explained two ways to print data inside
the DataGridView. Hopefully this exercise will give you some insight into printing one of
the more powerful controls inside the Windows Form in C#and .NET.

Conclusion

It is probably harder to deconstruct a bar code than to generate its code in .NET. The
brunt of the work consists of creating lookup tables to handle parity checking for
different positions. Some more lookup tables might be added to the program to improve
its capability. For example, a look up table for country codes and currency could
internationalizethe program a bit. Or, you could break the form out into an inherited
hierarchy of calculating bar code classes (as previously mentioned) in order to generalize
the bar code methods and improve the program design. Then you could build upon
existing bar code formats more easily. Anyway, this handy bar code program should get
you started in creating bar codes for your products so they can NET them at the register.

Summary

Printing functionality in the .NET Framework library is defined in the
Syst em. Dr awi ng. Pr i nt i ng namespace. In this article we discussed almost every
possible aspect of printing. We began by discussing the history of printing in Microsoft
windows. Then we explained printing-related functionality in the Microsoft .NET
Framework.

After a basic introduction to printing in .NET, you learned the basic steps required to
write a printing application. You also learned how printing differs from on-screen
drawing, and how to print simple text; graphics object such as lines, rectangle, and
circles, images, text files; and other documents.

The Pr i nt er Set t i ngs class provides members to get and set printer settings. We
discussed how to use this class and its members.

The .NET Framework library provides printing-related standard dialogs. You learned to
use the Pr i nt Di al og, Pr i nt Pr evi ewDi al og, and PageSet upDi al og classes
to provide a familiar Windows look and feel to your application.

Multipage printing can be tricky. You learned how to write an application with multipage
printing functionality.

At the end of this article we discussed how to write custom printing and page setup
dialogs using PageSet t i ngs and related classes. We also explained the advanced
custom print controller-related classes and how to use them in an application.

Finally, we provided sample custom applications to practice the printing classes
discussed throughout this article.
Practical .NET Series Web/C#/Graphics
Copyright 2007 Mindcracker LLC and Microgold Software Inc. 82

About C# Corner Authors Team

C# Corner Authors Team, led by Mahesh Chand and Mike Gold, founders of C# Corner is a
team of Microsoft .NET MVPs, Authors, Experts, and Consultants, who is dedicated to bring .NET
technology in an easy-to-understand approach with real-world ready-to-use applications. Contact
C# Corner Authors Team at authors@c-sharpcorner.com.

Das könnte Ihnen auch gefallen