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.