Document Toolkit: it's like reading a book
This is part four 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.
Related Links
- Part 1: Customizing the document viewer
- Part 2: Using the WebPackageReader
- Part 3: A better document service
- Document Toolkit Evaluation version
In this post I demonstrate how to use a custom book control to flip through the pages of an XPS document. An open source Silverlight Book control is available on CodePlex. We are going to adapt this control for use with XPS documents.
As I blogged in part one of this series it is very easy to customize the look and feel of the FixedDocumentViewer control by replacing the ItemsPanel displaying the document pages. Unfortunately the Silverlight Book Control is a stand-alone UserControl, so we need to take another approach here.
The UCBook control is a UserControl that queries for content using the IDataProvider interface. The IDataProvider is a custom interface and looks like this:
public interface IDataProvider
{
int GetCount();
object GetItem(int index);
}
We need to provide an implementation for IDataProvider where the GetCount() method should return the number of pages of an XpsDocument and where GetItem(int index) should return the page having the given index.
Loading document pages in Document Toolkit is achieved by using the XpsClient class and is a two-step process. All page information is available when a document is loaded. To display a page, the actual page contents needs to be loaded, which requires a seperate (asynchronous) load operation.
Once the contents of a page are loaded, it is visualized using the FixedPageViewer control. Normally, the FixedDocumentViewer takes care of page loading, visualizing and unloading. For we cannot use the FixedDocumentViewer in the BookControl, I have stuffed this behavior in a class BookData which implements the aforementioned IDataProvider interface.
When an XPS document has been loaded succesfully, an array of FixedPageViewer control is created. One FixedPageViewer wrapped in a Border for each document page.
// create page viewers
FixedDocument document;
this.pages = new Border[document.Pages.Count()];
for (int i = 0; i < this.pages.Length; i++) {
this.pages[i] = new Border() {
Child = new FixedPageViewer() { Scale = null }
}
Implementing the IDataProvider is relative easy, for we now have all page information stored in an array. The only thing left to do is load the actual page contents the moment a page is requested.
public int GetCount()
{
return this.pages.Length;
}
public object GetItem(int index)
{
var page = this.pages[index];
var viewer = (FixedPageViewer)page.Child;
if (viewer.FixedPage == null) {
var pageContent = this.document.Pages.GetPage(index + 1);
var settings = new LoadFixedPageSettings();
this.client.LoadFixedPageAsync(pageContent, settings, null);
}
}
When the page contents have been loaded, we assign it to the associated viewer.
private void client_LoadFixedPageCompleted(..)
{
// asign loaded page to its viewer
var page = this.pages[e.PageContent.PageNumber - 1];
var viewer = (FixedPageViewer)page.Child;
viewer.FixedPage = e.LoadFixedPage(null);
}
Run the sample.
Download the sample source code (requires Document Toolkit 1.0).
Sample XPS document courtesy of Laurence Moroney.
Published: June 30, 2009

very nice, looks great
This is how browsing trough a document should look. Great work. We might just use this in our application.