Printing WPF Annotations

Now that you have a document with highlights and notes your probably wondering how you can print these.  The easiest way to do it is using the built in Annotation print support.  The built in print mechanism will produce WYSIWYG (what you see is what you get) output, meaning that the notes will appear exactly as they do in your content.  So if the notes are minimized they will print minimized, if they are obstructing text on the screen they will also be obstructing text in the print out, etc.

Adding support for printing annotations is trivial.  I would have blogged about this earlier but was reluctant because of some known issues with printing that will unfortunately be present in the upcoming Beta 2 bits.  But since some people may be interested I’ll do it anyway and add this little disclaimer:

In Feb CTP this code will work for printing annotations on both FlowDocument and FixedDocument (including XPS) content. In Beta 2 this will work for Fixed content (including XPS) but not for Flow content. (Of course in the RTM version is will work for both again:-)).

Enough gibber-jabber, lets look at some code. Building on the code I’ve attached for my previous sample, we'll first override the default print behavior of the DocumentViewer Print button:

<DocumentViewer Name="Viewer" Grid.Row="1">
<DocumentViewer.CommandBindings>
<CommandBinding Command="ApplicationCommands.Print" Executed="OnPrint" />
</DocumentViewer.CommandBindings>
</DocumentViewer>

Now we add the event handler:

protected void OnPrint(object sender, EventArgs e)
{
   PrintDialog dialog = new PrintDialog();
   bool? result = dialog.ShowDialog();
   if (result != null && result.Value)
{
      XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(dialog.PrintQueue);
      AnnotationService service = AnnotationService.GetService(Viewer);
      AnnotationDocumentPaginator adp = new AnnotationDocumentPaginator(
_xpsDocument.GetFixedDocumentSequence().DocumentPaginator,
service.Store);
writer.Write(adp);
}
}

As you can see from the sample above, annotations are added to your document printout by wrapping the basic IDocumentPaginator with an AnnotationDocumentPaginator (ADP).  Something that is transparent in this example because of the way that XPS document work is that you should always pass a copy of your Document to the AnnotationDocumentPaginator.  If you don’t then the DocumentPaginator that is being displayed will get corrupted and after printing you may no longer be able to browse the document or interact with annotations properly. 

One last note is about synchronization.  There is no synchronization built into this print api.  Therefore, if you want to implement a background print you should clone your Annotation stream and then use the AnnotationDocumentPaginator constructor which accepts a Stream.  If you just pass the AnnotationStore directly then any changes you are making the live document may be represented in the partially printed document.