One might think that WPF is meant only for doing graphical user interface stuff, but it also contains an API to perform basic printing tasks. The printing API in WPF is actually more advanced than the one offered by windows forms so it will be a lot easier to work with.
Printing a basic visual
Printing something visual in WPF is dead simple, the following sample demonstrates how easy it is to print a basic photo (Contains actual code from the photoviewer application):
PrintablePhoto printable = new
PrintablePhoto(photo);
PrintDialog dlg = new
PrintDialog();
if(dlg.ShowDialog() == true)
{
Size printSize = new
Size(dlg.PrintableAreaWidth, dlg.PrintableAreaHeight);
Image img = new
Image();
img.Source = printable.ImageData;
img.Stretch = Stretch.UniformToFill;
img.Margin = new
Thickness(48);
dlg.PrintVisual(img,photo.Title);
}
The printable photo class here is a wrapper around a photo class that has the functionality required to load the image data for printing. The used ImageData property is an image representing the actual photo. This image instance can be printed by calling PrintVisual on the PrintDialog.
All the logic required for page setup etc is contained in the PrintDialog, so you don’t need to worry about that. I discovered just one thing that might be a bit strange. There are no page margins, so you will have to calculate those yourself. A unit of 96 for the margin is equal to an inch. The example has a margin of half an inch on all sides of the picture.
Printing a document with multiple pages
Printing a single image is fine, but most applications don’t do that. For example if you need to print invoices you are going to need logic that handles printing multiple pages. This is possible in WPF but requires a bit more work.
The basics of printing remain the same, except now PrintDocument is called. This method accepts a FixedDocumentSequence instance. This FixedDocumentSequence is actually an XPS document that you can either load from disk or generate on the fly.
PrintDialog dlg = new
PrintDialog();
if (dlg.ShowDialog() == true)
{
AlbumDocumentBuilder builder = new
AlbumDocumentBuilder();
builder.PageWidth = dlg.PrintableAreaWidth;
builder.PageHeight = dlg.PrintableAreaHeight;
FixedDocumentSequence sequence = builder.BuildDocumentSequence(album);
dlg.PrintDocument(sequence.DocumentPaginator, album.Title);
}
Building the document to print
Generating a document to print is not that hard. The first step in generating a fixed document for printing is creating the sequence and adding an empty document to it:
FixedDocument document = new
FixedDocument();
FixedDocumentSequence sequence = new
FixedDocumentSequence();
DocumentReference reference = new
DocumentReference();
reference.SetDocument(document);
sequence.References.Add(reference);
Next step is creating a page and adding it to the fixed document:
PageContent pageContent = new
PageContent();
document.Pages.Add(pageContent);
Defining page content
Once you have a fixed document sequence containing the document you want to print, you can add content to the page that you created. PageContent itself does not expose methods to add content, this can be achieved by casting the PageContent instance to IAddChild.
The following example demonstrates how you can add a UniformGrid to a page.
IAddChild childContainer = (IAddChild) page;
UniformGrid grid = new
UniformGrid();
grid.Columns = 2;
childContainer.AddChild(grid);
grid.Measure(pageSize);
grid.Arrange(new
Rect(pageSize));
Fixed document pages can contain a wide range of visual components, such as paragraphs and text runs. But you can also add inline images and UI components. Check MSDN for more information about documents.
You have full control over what you put on a single page, while still making use of the rich layout techniques offered by WPF.
Keep in mind however that you need to call arrange and transform yourself, otherwise you will end up with a blank page. Calling Measure and Arrange on the root object on the page is enough to get things going, because the root component will perform the Measure and Arrange operations on all its children automatically.
Conclusion
The amount of work required to print documents in WPF has been drastically reduced compared to what you need to do in windows forms to get something out of your printer. And thanks to XPS printing multiple pages isn’t all that hard anymore either.
Resources
- Information about documents in WPF: http://msdn.microsoft.com/en-us/library/ms748388.aspx#document_viewer
- More information on printing in WPF: http://msdn.microsoft.com/en-us/library/aa970449.aspx