Document Toolkit: Customizing the document viewer
This is part one of a series of blog posts on Document Toolkit. Document Toolkit is a Silverlight library offering a range of features that enable easy document access and document display in Silverlight 2 and Silverlight 3 applications.
If you want to experiment with Document Toolkit, I highly recommend downloading the fully functional evaluation version of Document Toolkit. You can use the evaluation version to try out the topics discussed in this series. A download link with the complete sample source code is available at the bottom of this page.
In this post I demonstrate how to customize the user interface elements of the document viewer. Document Toolkit consists of two assemblies; FirstFloor.Documents contains the types of the core object model and FirstFloor.Documents.Controls provides the user interface elements for displaying XPS documents.
Document Toolkit Controls
The single most important control in the FirstFloor.Documents.Controls assembly is the FixedDocumentViewer.

Figure 1. FixedDocumentViewer
The FixedDocumentViewer loads and displays the pages of an XPS document. Once supplied with an instance of FixedDocument, the viewer is capable of loading and unloading pages on demand. The viewer implements a proper disposal pattern causing it to unload pages that are not in the visible area. Thanks to the concept of Package Readers (explained in a future blog post), the viewer is not required to load an entire document in memory, it only needs to load the visible pages. This allows for fast display of pages even in very large XPS documents.
All controls in the FirstFloor.Documents.Controls assembly implement the so-called Silverlight Parts & States model. The Parts & States model allows for complete customization of controls, where the contents of a control can be replaced entirely. For more details on the Parts & States model I suggest you read the excellent Parts & States blog posts by Karen Corby.
The document viewer in Document Toolkit consists of four UI elements. First there is the FixedDocumentViewer as described above. The FixedDocumentViewer defines two parts, a PagesControl and a ScrollViewer as outlined in figure 2.

Figure 2. FixedDocumentViewer parts
The PagesControl is a control that is used to present a collection of pages. PagesControl derives from ItemsControl and inherits all its features such as item templating, databinding, etc.
The PagesControl class creates PageItem instances for each page in the document. A PageItem defines a number of visual states for selection and mouse states. The PageItem control is similar to a ListBoxItem control.
PageItem defines a single part of type FixedPageViewer. The FixedPageViewer is the control displaying a single page which automatically scales to fit the available area. FixedPageViewer is closely modelled after the ViewBox control from Silverlight Toolkit.
Styling
Since all controls implement the Parts & States Model, it is really easy to replace the control's content. The following XAML snippet displays (a part of) the default style of the PageItem control. The style defines a border with a black stroke and a white background that is applied to each page being viewed.
<Style TargetType="controls:PageItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:PageItem">
<Border x:Name="Border" Background="White" BorderBrush="Black" BorderThickness="1" Margin="4" HorizontalAlignment="Center" VerticalAlignment="Center" >
<controls:FixedPageViewer x:Name="PageViewer"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now, I am about to modify the PageItem style and add a drop shadow effect. You need Silverlight 3 Beta to display the drop shadow effect, for effects were introduced in SL3. The following XAML snippet defines the custom PageItem style with a drop shadow. The page border margin is increased to 8 pixels in order to create some room for the drop shadow.
<Style x:Key="MyPageItemStyle" TargetType="controls:PageItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:PageItem">
<Border x:Name="Border" Background="White" BorderBrush="Black" BorderThickness="1" Margin="8" HorizontalAlignment="Center" VerticalAlignment="Center" >
<Border.Effect>
<DropShadowEffect Color="Black" ShadowDepth="10" />
</Border.Effect>
<controls:FixedPageViewer x:Name="PageViewer"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In order to view the custom style we need to modify the FixedDocumentViewer style and make sure each created PageItem uses the custom style. The default FixedDocumentViewer style is shown in the following snippet;
<Style TargetType="controls:FixedDocumentViewer">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:FixedDocumentViewer">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer x:Name="ScrollViewer" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Visible">
<controls:PagesControl x:Name="PagesControl" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
To use the custom PageItem Style, we specify a custom ItemContainerStyle on the PagesControl. Note that this styling behavior is similar to styling a ListBox.
Not only do I want to add a drop shadow, I want to change the way the pages are arranged as well. Since PagesControl derives from ItemsControl we can specify an ItemsPanel. The ItemsPanel is the panel used to layout the pages. By default a StackPanel is used with a vertical orientation. For this sample I want to layout my pages horizontally. To make this work I simply need to set the ItemsPanel to a StackPanel with Horizontal orientation.
<Style x:Key="MyViewerStyle" TargetType="controls:FixedDocumentViewer">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:FixedDocumentViewer">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer x:Name="ScrollViewer" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<controls:PagesControl x:Name="PagesControl" ItemContainerStyle="{StaticResource MyPageItemStyle}">
<controls:PagesControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</controls:PagesControl.ItemsPanel>
</controls:PagesControl>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Figure 3 displays the custom styled FixedDocumentViewer where each page has a drop shadow effect and the pages are arranged horizontally.

Figure 3. Customized FixedDocumentViewer
Custom Panels
Replacing the ItemsPanel is a very powerful feature. Jeff Prosise posted the source code of a RadialPanel recently. I have included the RadialPanel in the sample source code and using this RadialPanel the pages are arranged radially as is demonstrated in the figure below. Any panel class can be used to arrange the pages of a document. This may prove very useful if you have specific requirements regarding the layout of document pages.

Figure 4. Radially arranged pages
Summary
Document Toolkit controls are based on the Parts & States Model. The Parts & States model allows you to completely replace the control's contents and provides a mechanism to customize the look & feel of the document viewer so that it completely suits your needs.
Download the sample source code (requires Document Toolkit)
Published: May 6, 2009
Any plans on implementing a print function? This i sthe biggest problem we have with using Silverlight. You have to create PDF files in order to print reports.
Bill: printing is a feature that should be added to SL by Microsoft. There is not a lot I can do about it. You can download an XPS document to local disk and print it using the standard XPS viewer, no need to create a PDF file.
How about adding printing using writeablebitmap silverlight.net/.../95308.aspx
Also could you add search, select, copy text support. This may require a hidden yet selectable textbox over your content like on www.codeproject.com/.../SL2TextBoxWsSyn
slyi: selection features will be available in the upcoming 1.1 version which is scheduled for June 2009