[C# Helper]
Index Books FAQ Contact About Rod
[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

[C# 24-Hour Trainer]

[Beginning Software Engineering]

[C# 5.0 Programmer's Reference]

[MCSD Certification Toolkit (Exam 70-483): Programming in C#]

Title: Provide print previews and printing for Windows Forms applications in C#


This example shows how you can support print previews and printing for a Windows Forms application in C#.

A PrintDocument plays a central role in printing and print previews. It raises its PrintPage event to generate graphics for printing.

A PrintPreviewDialog can display a preview for a PrintDocument object.

You can create these objects in code but it's easier to create them at design time. Add a PrintDocument object and a PrintPreviewDialog object to the form. Set the PrintPreviewDialog's Document property to the PrintDocument object. When the PrintPreviewDialog needs to display a print preview, it uses the PrintDocument object to generate the graphics it should display.

Next give the PrintDocument a PrintPage event handler to generate the pages. The event handler should use the Graphics object provided by the e.Graphics parameter to generate graphics.

When the event handler is finished, it should set e.HasMorePages to true or false to indicate whether there are more pages to print.

The following code shows this example's PrintPage event handler. It displays shapes and page numbers on four pages. This is the most interesting part of the printing process.

// Print the document's pages. private int NextPageNum = 0; private void pdocShapes_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { // Draw a shape depending on the page we are printing. switch (NextPageNum) { case 0: // Draw an ellipse. using (Pen the_pen = new Pen(Color.Red, 10)) { e.Graphics.DrawEllipse(the_pen, e.MarginBounds); } break; case 1: // Draw a triangle. using (Pen the_pen = new Pen(Color.Green, 10)) { int xmid = (int)(e.MarginBounds.X + e.MarginBounds.Width / 2); Point[] pts = { new Point(xmid, e.MarginBounds.Top), new Point(e.MarginBounds.Right, e.MarginBounds.Bottom), new Point(e.MarginBounds.Left, e.MarginBounds.Bottom), }; e.Graphics.DrawPolygon(the_pen, pts); } break; case 2: // Draw a rectangle. using (Pen the_pen = new Pen(Color.Blue, 10)) { e.Graphics.DrawRectangle(the_pen, e.MarginBounds); } break; case 3: // Draw a diamond. using (Pen the_pen = new Pen(Color.Orange, 10)) { int xmid = (int)(e.MarginBounds.X + e.MarginBounds.Width / 2); int ymid = (int)(e.MarginBounds.Y + e.MarginBounds.Height / 2); Point[] pts = { new Point(xmid, e.MarginBounds.Top), new Point(e.MarginBounds.Right, ymid), new Point(xmid, e.MarginBounds.Bottom), new Point(e.MarginBounds.Left, ymid), }; e.Graphics.DrawPolygon(the_pen, pts); } break; } // Draw the page number centered. using (StringFormat sf = new StringFormat()) { sf.Alignment = StringAlignment.Center; sf.LineAlignment = StringAlignment.Center; using (Font the_font = new Font("Times New Roman", 200, FontStyle.Bold)) { using (Brush the_brush = new SolidBrush(Color.Black)) { e.Graphics.DrawString(String.Format("{0}", NextPageNum + 1), the_font, the_brush, e.MarginBounds, sf); } } } // Next time print the next page. NextPageNum += 1; // We have more pages if wee have not yet printed page 3. e.HasMorePages = (NextPageNum <= 3); // If we have no more pages, reset for the next time we print. if (NextPageNum > 3) NextPageNum = 0; }

The class-level variable NextPageNum indicates the next page to print. initially it's set to 0 so the program prints its first page.

The PrintPage event handler uses a switch statement to display different shapes on different pages. You can look through the code to see how the program draws each of the pages.

After it draws the appropriate shape, the code draws the page number centered.

Next the program increments NextPageNum and sets e.HasMorePages to true if NextPageNum is less than or equal to 3. (That makes it print 4 pages.)

Finally, if NextPageNum is greater than 3, the program has generated all of the pages. In that case, the code resets NextPageNum to 0 for the next time the program needs to generate the printout.

After you write the PrintPage event handler, the rest is easy. The following code shows how the program displays a print preview and how it prints.

// Display a print preview. private void btnPreview_Click(object sender, EventArgs e) { ppdShapes.ShowDialog(); } // Print. private void btnPrint_Click(object sender, EventArgs e) { pdocShapes.Print(); }

To display a print preview, the program just calls the PrintPreviewDialog's ShowDialog method. The dialog uses its associated PrintDocument to generate the graphics it needs, and it displays the results.

To print, the program calls the PrintDocument's Print method. The print out goes immediately to the computer's default printer.

Note that there is no easy way to tell in advance how many pages the printout will include, so you cannot print things like "Page 1 of 12." To do that, you need to examine whatever you are printing before you start the printout and figure out how many pages there will be ahead of time.

(In a later post I'll discuss other useful PrintDocument events.)

Download the example to experiment with it and to see additional details.

© 2009-2022 Rocky Mountain Computer Consulting, Inc. All rights reserved.