Tag - Printing

How to print a List<string> in Silverlight 4 Beta over multiple pages?!

On www.silverlight.net several people are asking how to print the values of a DataGrid in Silverlight. You cannot just assign the DataGrid to the PageVisual-Property of the PrintPageEventArgs. This would just print the DataGrid as it is on one page. The data wouldn’t be splitted on several pages, cause there’s no paging logic to use. You’ve to write this logic.

You’re responsible for the paging! But how to do it? In this post I’ll give you a little idea how it could work by simple printing out a List of string-values. I won’t talk a lot about the details. Just look at the code below:

When the Button_Click-Eventhandler is executed, the List gets printed over 5 pages. You can easily print it to PDFCreator or XPS Printer to test it. The output looks like this:


Download the source here and enjoy. Give me feedback by entering a comment to this blogentry or via email on www.thomasclaudiushuber.com/blog.

How to print dynamically created Images in Silverlight 4 Beta

Silverlight 4 supports printing scenarios. It’s quite easy. Just create a PrintDocument instance, handle the PrintPage-Event and call the Print-Method. In the PrintPage-Event set the PageVisual-Property of the PrintPageEventArgs to a UIElement of your choice. If there are more pages, set the HasMorePages-Property of the PrintPageEventArgs to true and the PrintPage-Eventhandler would be called again for the next page.

Below a simple example using a lambda expression. When the Print-Method is called a PrintDialog is displayed to the User, where he can select the printer of his choice. When the PrintDialog was accepted, the PrintPage-Event gets fired and the lambda expression below get’s called. The PageVisual-Property is set to a TextBlock. So that TextBlock with the text “Thoams says…” is printed out.

Ok, so far so good. As I was working on an example for my upcoming Silverlight 4 book I needed to create an Image-Element on the fly and print this out. And then I noticed that the Image doesn’t appear on the output.

While searching for a solution I found somebody having the same problem in this thread in Microsoft’s Silverlight forums:


So, it seemed it was not my cause, it was a Beta-cause. So let’s look at a workaround. But first look at the bug.

I made a smaller example to reproduce it. View the following code. What do you think is printed on the page?

Right, an Image should be printed on the page. But it isn’t. The page is empty. Well, the next thing I tried was to call Measure, Arrange and UpdateLayout on the Image to force a layout-pass. But anyway, it didn’t work, the printed page is always empty.

When the Image isn’t created on the fly, it works. Define the Image in XAML like this

and a Print-Method in the Codebehind-File would work like that:

But we want to print an Image on the fly. So how to do that? One way I found out was to create an ImageBrush and set its ImageSource-Property to the BitmapImage. Use the ImageBrush for a Rectangle’s Fill-Property and print out that Rectangle. So here is some code to dynamically print an image by using an ImageBrush in combination with a Rectangle:

And voilà, the output looks like this when printed to my PDFCreator-Printer:


[Download the Source]

Cheers Thomas

WPF Printing: How to print a PageRange with WPF’s PrintDialog – that means the user can select specific pages and only these pages are printed

Printing a Page Range isn’t as easy as it supposed to be. So in this blog-post you’ll see a very easy method to print specific pages from a XPS-Document. But before we look at the solution, let’s start with the problem.

The Problem

WPF’s PrintDialog has a UserPageRangeEnabled-Property. Set this property to true before you show the PrintDialog. Then the user is allowed to enter a Pagerange in the PrintDialog. The problem is that whatever the user enters, in each case all pages are printed. The PrintDialog itself has no logic to print some specific pages. Let’s look at an example.

Below the small UI that consists of a Button and a DocumentViewer. This code belongs to the MainWindow.xaml-File.

The Codebehind-File MainWindow.xaml.cs has an EventHandler for the Loaded-Event of the Window. There a XPS-Document with five pages is loaded into memory. The FixedDocument-Instance contained in that XPS-Document is stored in the _fixedDocument-Field and displayed in the DocumentViewer called viewer – the latter we declared above in XAML.

So we have the necessary thing for testing a “print-range”-scenario: A FixedDocument-Instance in memory, stored in the _fixedDocument-Field. Let’s look at the PrintButtonClick-Eventhandler that contains the logic to print. The Eventhandler is shown below. First a PrintDialog is created. Then we set the UserPageRangeEnabled-Property to true, show the Dialog by calling the ShowDialog-Method. Is the return-value true we call the PrintDialog’s PrintDocument-Method by passing in the DocumentPaginator of the FixedDocument. Also a string is passed in that is displayed in the printer queue as jobname.

Now what happens? Let’s look how we use the application. When starting up the application, the FixedDocument with five pages is displayed in the DocumentViewer:


When the “Print”-Button is pressed, the PrintDialog comes up. I select a PageRange of 2-3 like shown below. For testing purposes I always print in the PDFCreator that creates a PDF-Document with the output. There are several other ways. You could also print in the XPS-Document-Writer (even if it’s a little bit doubled when printing a xps to the XPS-Document-Writer).


Now even with the Pages of 2-3 selected, the “printed” PDF looks like below. It contains all five pages of my document. But it should contain only the pages 2 and 3.


So let’s summarize the problem: It doesn’t matter what you select as a PageRange in the PrintDialogs Pages-Field. It’s up to you to check the Pages and print out only that range. The PrintDialog doesn’t care anything about the PageRange.

The PrintDialog has the Property PrintRange that contains a PrintRange–object with PrintFrom- and PrintTo-Properties. It also has a Property called PageRangeSelection that contains the value PageRangeSelection.UserPages when a PageRange was entered. But the logic to print out that specified range is your work. And this work needs some WPF know-how to do. So let’s look at the solution(s). :-)

A bad solution

I call the first one a bad solution because it is not an easy to manage one. This solution is to make a new FixedDocument that only contains the pages you need. You can implement such a logic based on the things you find in this codeproject-article:


In my mind creating a new XPS-Document just for printing is a bad solution. I think a good solution would be to just be able to print some pages of an existing xps-Document/FixedDocument. So let’s look at the good one.

A good solution (I hope so ;-))

The good solution is the one I’ve implemented today and finished in the train from Zurich to Basel. I’ve not tested every scenario, but it seems to work great. If you have any hints to this solution, let me know.

The first thing you have to know is that the pages used for the output are created by a DocumentPaginator. This was passed to the PrintDocument-Method of the PrintDialog some lines above. The DocumentPaginator-class itself is abstract. Beside some members it defines a Method GetPage(int pageNumber) that returns the DocumentPage for the passed in pageNumber. Now the idea is to create a wrapper-class for the DocumentPaginator that is itself also of type DocumentPaginator. And now guys, what pattern is that? ;-) Doesn’t matter.

So we create a DocumentPaginator and let’s call it PageRangeDocumentPaginator. It encapsulates a DocumentPaginator and can return a specific (page)range of the encapsulated DocumentPaginator. Therefore the constructor takes two parameters: a DocumentPaginator to encapsulate and a PageRange-object that contains PageFrom and PageTo-Properties, both of type int. The PageRange-structure exists in the Namespace System.Windows.Controls.

The PageRangeDocumentPaginator-class is listed below. In the constructor the passed in DocumentPaginator is stored in the _paginator-field. The pageRange-values are stored in the fields _startIndex and _endIndex. As the PageRange starts with 1, we substract 1 to get the zero-based index. In the final line of the constructor the _endIndex is adjusted. If the user enters a higher pageNumber than the Document contains, _endIndex will point to the index of the last page.

Now look at the override of the GetPage-Method. There gets just the GetPage-Method of the encapsulated DocumentPaginator called. But the _startIndex is regarded. Now look at the PageCount-Property. It uses the _startIndex and _endIndex to calculate the pageNumbers. IsPageCountValid always returns true and the Properties PageSize and Source simply pass the responsibility to the underlying DocumentPaginator. That’s it. Now look how to use the class in the PrintButtonClick-Eventhandler.

The PrintButtonClick-Eventhandler just needs a little if-statement. The PrintDialog has a Property called PageRangeSelection of Type PageRangeSelection (Enum). The PageRangeSelection-Enum contains the values AllPages and UserPages. When the User has entered a PageRange, that Property would have the value UserPages. In that case I use the PageRangeDocumentPaginator-class and pass in the DocumentPaginator of the FixedDocument and the PageRange from the PrintDialog. If the PageRangeSelection-Property contains not the value UserPages, we print all pages as we’ve already done in the problem-scenario. So the code looks like this:

When the user has selected a PageRange the PageRangeDocumentPaginator is used to generate the pages for the output. When I test the code with a PageRange of 2-3 as in the problem-section, I now retrieve the expected output of the two pages 2 and 3, as my “printed” PDF shows:


That’s it. Enjoy the code and download the solution here. And don’t forget to kick this post for me:

[Download Thomas PrintingProject]

kick it on DotNetKicks.com

Cheers Thomas

PS: As time and my sparetime is limited – I’m writing on my Silverlight 4.0 book and an update of my WPF book in my sparetime – I can’t give any free support for the code. Use it or not. But feel free to contact me for any suggestions via: