Earlier we saw that many Windows components work together to generate your printed output. Within your .NET code, you will also use many components (classes) to drive the printing process. There are four main steps involved (at least directly) in printing a document from your code.
Let's try a little code to see how this printing beast eats. Or prints. Or whatever it does. How about a simple program that prints a five-page document on the user's selected printer? The output will be a large single-digit page number, perfect for the Sesame Street set. First, let's create a new Windows Forms application, and add a single button to Form1 named ActPrint. We'll also add a PrintDocument control (named CountingDoc), and a PrintDialog control (named UserPrinter). Figure 19-5 shows the form and its supporting controls.
Figure 19-5. A program with only printing on its mind
These controls implement the first two of our four-step printing process. Next, we'll add the source code.
Public Class Form1 Private WhichPage As Integer Private Sub ActPrint_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles ActPrint.Click ' ----- Prompt the user for printer settings, and ' start printing. UserPrinter.Document = CountingDoc If (UserPrinter.ShowDialog() = _ Windows.Forms.DialogResult.OK) Then _ CountingDoc.Print() End Sub Private Sub CountingDoc_BeginPrint(ByVal sender As Object, _ ByVal e As System.Drawing.Printing.PrintEventArgs) _ Handles CountingDoc.BeginPrint ' ----- Start the counting over. WhichPage = 1 End Sub Private Sub CountingDoc_PrintPage(ByVal sender As Object, _ ByVal e As System.Drawing.Printing. _ PrintPageEventArgs) Handles CountingDoc.PrintPage ' ----- Print a single page. Dim hugeFont As Font Dim centeredText As StringFormat ' ----- Let's go overboard on the font: 256 points! hugeFont = New Font("Arial", 256) ' ----- Center the text on the page. centeredText = New StringFormat() centeredText.Alignment = StringAlignment.Center centeredText.LineAlignment = StringAlignment.Center ' ----- Print the number. e.Graphics.DrawString(CStr(WhichPage), hugeFont, _ Brushes.Black, e.MarginBounds, centeredText) ' ----- Draw the page margins to make it clear where ' they are. e.Graphics.DrawRectangle(Pens.Blue, e.MarginBounds) ' ----- Limit the output to five pages. WhichPage += 1 If (WhichPage <= 5) Then e.HasMorePages = True _ Else e.HasMorePages = False End Sub End Class
This code implements steps three (ActPrint_Click) and four (CountingDoc_PrintPage). The ActPrint button's Click event handler links the document and the Print Dialog so that they both refer to the same settings. It then prompts the user to select a printer and various options through the ShowDialog call. If the user clicks the OK button on that dialog, it triggers a call to the document's Print method.
The action then moves to the events of the PrintDocument instance. I've implemented two of the events: a BeginPrint event handler that performs some initialization, and a PrintPage event handler that does the hard work. (Other events include EndPrint, used to clean up when printing is complete, and QueryPageSettings, where you change the orientation and settings of each page of the document.) Actually, it's not all that hard, especially since we saw similar code in the chapter on GDI+. The biggest difference is the amount of space available on a printed page, allowing us to play with fonts in the hundreds of point sizes.
Figure 19-6 shows page two of the output from this program. I printed to the pseudo-printer installed with Microsoft's Windows Journal application. You can see in the bottom-right corner that it did properly record five output pages.
Figure 19-6. This page is brought to you by the number 2