From Computejobs.ie

An Absolute Beginners Guide to Printing in .NET
By Duncan Jones
Jan 28, 2008, 15:33

The print system

Although it is possible to live a happy and fulfilling life without ever looking under the bonnet at the print subsystem it does make it slightly easier to write an application that has hardcopy capabilities if you have some understanding of what the operating system does in response to the “print” command.

The first thing an application needs to know in order to print is what print device to print to. To achieve this it queries the spool server and asks it to return a list of the devices attached, and some basic information about them (name, location, device driver etc.)

Then the user selects one and the application obtains a handle that refers to that printer, through which it queries the device settings (such as the paper size it uses, resolution etc.) and then it obtains a device context on which to draw the first page. Drawing the page is done with the standard GDI drawing commands such as ExtTextOut, Rectangle, Polygon etc.

Once the page is drawn the application either notifies the spool system that the job is complete or requests another page. At this stage the drawn page can be translated into the printer control language appropriate to the printer by the printer driver and the hardware can do its thing.

In between pages the application can also make changes to the settings of the printer so that, for example, one page can be printed landscape and the next portrait etc.

Whenever the application or the printer performs an action on the print job a notification is raised so that any application which monitors print jobs can be notified of their progress and so that any problems that occur printing the document can be notified to the user to rectify them.

Printing in .NET

Printing in .NET follows the overview of the print system quite closely. There are two main framework classes that you use to do all your work with printing which are in the System.Drawing.Printing namespace: PageSettings (which is used for such things as selecting the paper size and landscape or portrtait) and PrintDocument which is used to do the printing operation itself.

Arguably the best way of implementing a custom print operation in .NET is to create your own class that holds a private variable that is of type PrintDocument and write the code to perform the printing in the event handlers of that class to print the desired document.  I will dicuss these in the order in which they occur in the life of a print operation.

BeginPrint

The BeginPrint event is raised when the print job is initiated.  You should use this event to do any setting up that will be required to perform the print job: set the data pointers (if any) to the start position and initialise any page number variables you might have.

 Private Sub PrintDocument_Form_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument_Form.BeginPrint

QueryPageSettings 

The QueryPageSettings event is raised before each and every page that is printed.  You use this event to set any page settings for the next page to be printed.  You can set the orientation (landscape or protrait), the paper size, paper source and so on.  In this example we want page 3 in landscape:

 Private Sub PrintDocument_Form_QueryPageSettings(ByVal sender As Object, ByVal e As System.Drawing.Printing.QueryPageSettingsEventArgs) Handles PrintDocument_Form.QueryPageSettings

   If _LogicalPageNumber = 3 Then

     e.PageSettings.Landscape = True

  Else

     e.PageSettings.Landscape = False

  End If

End Sub

PrintPage

All of the actual printing on a page is done in the PrintPage event handler.  This event is raised for each page that is printed, and the drawing and text commands that you code in this event handler control what is printed on the page itself.

Private Sub PrintDocument_Form_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument_Form.PrintPage

At the end of each page you decide if there are more pages to print, set the e.HasMorePages property to true and the QueryPageSettings and PrintPage events will be triggered again.  It is important to remember that the same event handler so if you want to print different pages you need to keep track of which page you are on and code your PrintPage event handler accordingly.

EndPrint

When the last page is printed (and you have told the print system that there are no more pages to follow) the EndPrint event is raised.  You can use this event handler to clear up any objects that you have created for the print job.

Hints and tips

  •  Graphics measurements in printing are in tenths of a millimeter - e.g. to print a rectangle 4 x 5 centimeters you would use e.Graphics.DrawRectangle(Pens.Black, 10, 10, 4000, 5000)
  • Z-Order (such as it is) is defined by teh order that print commands are issued - i.e. later drawing commands print on top of earlier ones

I hope this article gives you enough insight to allow you to approach the .NET printing subsystem.  Once you do you will find it is a very powerful part of the framework which will help in producing more fully featured windows applications.



© Copyright Computejobs.ie 2006