Charles Petzold

WPF Printing II

February 23, 2006

A few days ago I confessed that I couldn't get the WPF PrintDialog to print an arbitrary Visual object, e.g., a panel. A kind correspondent recommended I subject the Visual to a layout pass. Because I've read Chapters 10, 11, and 12 of my forthcoming book, I know that layout involves calls to Measure and Arrange. Without these calls the Visual has a zero dimension, which doesn't quite register on the printed page.

It works! The PrintaBunchaButtons.csx (and rename to .cs) program (PrintaBunchaButtons.csproj project file) demonstrates how it's done. After showing a PrintDialog, the program creates a Grid, gives it a gradient brush, populates it with 25 buttons of various sizes, and then calls the grid's Measure method. This causes the Grid to call Measure on each of its children, and those children, etc, etc. The result is that Grid calculates a DesiredSize property that is adequate to fit its contents.

The PrintaBunchaButtons program then uses DesiredSize and the size of the printer page to calculate a upper-left corner of the Grid that centers it on the page. A call to the grid's Arrange method cements the deal. (Grid, or course, calls Arrange on its children, etc, etc.)

The final step is a call to PrintVisual to print the Grid on the page.

It is possible to call PrintVisual multiple times and print multiple pages, but each call to PrintVisual is considered a separate print job. Printing multiple pages in the same print job is better handled through the PrintDocument method that I hope to discuss in a blog entry within the next few days.