The .NET Framework has made it very simple for you to support printing in your .NET applications. In this article, I will show you the basics of printing in .NET 2.0, and how you can configure page setup, print multiple pages, preview a document before it is printed, as well as let users select a printer to which to print.
Using Visual Studio 2005, create a new Windows application project using Visual Basic. In .NET, all the printing functionality is encapsulated within the PrintDocument control, which can be found in the Toolbox (see Figure 1). The PrintDocument control defines the various methods that allow you to send output to the printer.
To incorporate printing functionality into your Windows application, you can either drag and drop the PrintDocument control onto your form, or create an instance of the PrintDocument class during runtime. For this article, I will use the latter approach.
Figure 1. Locating the PrintDocument control in ToolBox
To start the printing process, use the Print() method of the PrintDocument object. To customize the printing process using the PrintDocument object, there are generally three events that you need to get acquainted with. They are:
Populate the default Form1 with a PictureBox control and a Button control (see Figure 2). Set the PictureBox control to display an image (here, I have displayed a 2D barcode [QRCode]).
Figure 2. Populating the default Form1 with the various controls
Switch to the code-behind of Form1 and import the following namespace:
Declare the following member variables:
Public Class Form1 '---font variables--- Private f_title As Font Private f_body As Font '---page counter--- Private pagecounter As Integer '---PrintDocument variable--- Dim printDoc As PrintDocument()
When the form is loaded, create an instance of the PrintDocument class and wire up the three main event handlers described earlier:
Private Sub Form1_Load( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load '---create an instance of the PrintDocument class--- printDoc = New PrintDocument '---set the document name--- printDoc.DocumentName = "Printing from Windows Forms" '---wire up the event handlers--- AddHandler printDoc.BeginPrint, _ New PrintEventHandler(AddressOf Me._beginPrint) AddHandler printDoc.PrintPage, _ New PrintPageEventHandler(AddressOf Me._printPage) AddHandler printDoc.EndPrint, _ New PrintEventHandler(AddressOf Me._endPrint) End Sub
In the event handler for the BeginPrint event, initialize the page counter as well as the fonts of the text to be used for printing the page:
Private Sub _beginPrint( _ ByVal sender As Object, _ ByVal e As PrintEventArgs) '---initialize the page counter--- pagecounter = 1 '---initialize the fonts--- f_title = New Font("Arial", 16, FontStyle.Bold) f_body = New Font("Times New Roman", 10) End Sub
In the EndPrint event handler, de-reference the font variables used:
Private Sub _endPrint( _ ByVal sender As Object, _ ByVal e As PrintEventArgs) '---de-reference the fonts--- f_title = Nothing f_body = Nothing End Sub
Finally, the event handler for the PrintPage event is the place where you do the bulk of the work sending the output to the printer. Basically, you use the Graphics object in the PrintPageEventArgs class to specify the output you want to print. For example, to draw a rectangle you would use the e.Graphics.DrawRectangle() method (where e is an instance of the PrintPageEventArgs class). To print a string, you use the e.Graphics.DrawString() method:
Private Sub _printPage( _ ByVal sender As Object, _ ByVal e As PrintPageEventArgs) Dim g As Graphics = e.Graphics '---draws the title--- g.DrawString("2D Barcode for Learn2Develop.net", _ f_title, Brushes.Black, _ 20, 30) '---draws a border--- Dim border As Rectangle = _ New Rectangle(10, 10, _ 500, 240) g.DrawRectangle(Pens.Black, border) '---draws the barcode--- If PictureBox1.Image IsNot Nothing Then g.DrawImage(PictureBox1.Image, 20, 60, _ PictureBox1.Size.Width, _ PictureBox1.Size.Height) End If '---draws the page count--- g.DrawString("Page " & pagecounter, _ f_body, Brushes.Black, _ 20, 220) '---increments the page counter--- pagecounter += 1 End Sub
When the user clicks on the Print button, send the output directly to the default printer using the Print() method of the PrintDocument object:
Private Sub btnPrint_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnPrint.Click '---print straight to printer--- printDoc.Print() End Sub
You can view the name of the document printed by selecting your default printer in Start | Settings | Printers and Faxes (see Figure 3).
Figure 3. Locating the document sent to the default printer for printing
Instead of sending the output directly to the printer, it is always good to allow the user to preview the output before he sends it to the printer for printing. This can be achieved using the PrintPreviewDialog() class:
Private Sub btnPrint_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnPrint.Click '---show preview--- Dim dlg As New PrintPreviewDialog() With dlg .Document = printDoc .ShowDialog() End With End Sub
The above code previews the output in a separate window. Here, you can click on the printer icon to send the output to the printer. You can also choose to enlarge the page or view multiple pages on one single screen (see Figure 4).
Figure 4. Previewing the print output
Note that when you click on the printer icon in the Print Preview window to print the output, all the various event handlers for the PrintDocument class will be fired again. Because of this, be sure to initialize all necessary variables that are used for the printing in the BeginPrint event handler.
If you have a series of pages to print, you need to do some work. In the default Form1, add the Label and Text controls as shown in Figure 5 and name the two TextBox controls as shown.
Figure 5. Adding the additional controls to Form1
Here, we want to let users print a series of pages. Users can enter the required series of pages to print and the individual pages will be printed.
In the event handler for BeginPrint, initialize the page counter variable as shown in bold below:
Private Sub _beginPrint( _ ByVal sender As Object, _ ByVal e As PrintEventArgs) '---initialize the page counter--- pagecounter = CInt(txtFrom.Text) '---initialize the fonts--- f_title = New Font("Arial", 16, FontStyle.Bold) f_body = New Font("Times New Roman", 10) End Sub
In the PrintPage event handler, you will determine if there are any more pages to print. If there are, setting the HasMorePages property of the PrintPageEventArgs class to True will cause the PrintPage event handler to be fired one more time. Once there are no more pages left to print, set the HasMorePages property to False.
Private Sub _printPage( _ ByVal sender As Object, _ ByVal e As PrintPageEventArgs) ... '---increments the page counter--- pagecounter += 1 '---determine if you have more pages to print--- If pagecounter <= txtTo.Text Then e.HasMorePages = True Else e.HasMorePages = False End If End Sub
Figure 6 shows the user selecting to print from page 2 to 5, and the corresponding page output starting from page 2. You can navigate to other pages by clicking on the up/down arrows located at the top right corner of the preview window.
Figure 6. Previewing the multiple page output
If you have multiple printers attached to your computer, it is a good idea to let the user choose the desired printer instead of sending the output to the default printer. You can do so via the PrintDialog class, which is demonstrated below:
Private Sub btnPrint_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnPrint.Click '---let user select a printer to print--- Dim pd As New PrintDialog With pd .Document = printDoc .AllowSomePages = True End With Dim result As DialogResult = pd.ShowDialog() If result = Windows.Forms.DialogResult.OK Then printDoc.Print() End If End Sub
Figure 7 shows how the PrintDialog class looks like when it is shown.
Figure 7. Letting the user choose a printer to which to print
You can set some default values for the PrintDialog class, such as the following properties in bold:
Dim pd As New PrintDialog With pd .Document = printDoc .AllowSomePages = True .PrinterSettings.Copies = 3 .PrinterSettings.FromPage = 2 .PrinterSettings.ToPage = 5 End With
Figure 8 shows the default values set.
Figure 8. Printer selection dialog with some default values set
It is always a good practice to inform the user when the printing is completed. To do so, simply display a message in the EndPrint event handler, such as the following:
Private Sub _endPrint( _ ByVal sender As Object, _ ByVal e As PrintEventArgs) '---de-reference the fonts--- f_title = Nothing f_body = Nothing MessageBox.Show(printDoc.DocumentName & _ " has finished printing.") End Sub
Besides letting the user choose the printer to print to, it would also be useful to let users configure the page setup so that he can choose the page details, such as page orientation, paper size, etc. To demonstrate this, add a Button control to the page (see Figure 9) and code it as shown below:
Figure 9. Adding a Page Setup Button control
Private Sub btnPageSetup_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnPageSetup.Click Dim pageSetup As New PageSetupDialog With pageSetup .PageSettings = printDoc.DefaultPageSettings .ShowDialog() End With End Sub
Figure 10 shows how the PageSetupDialog class looks like when shown.
Figure 10. Configuring Page Setup
In this article, you have seen the main steps in enabling printing in your Windows application. Does your application support printing? Use the talkback links below to share your thoughts with our readers.
Wei-Meng Lee (Microsoft MVP) http://weimenglee.blogspot.com is a technologist and founder of Developer Learning Solutions http://www.developerlearningsolutions.com, a technology company specializing in hands-on training on the latest Microsoft technologies.
Return to Windows DevCenter.
Copyright © 2009 O'Reilly Media, Inc.