FlowDocuments are to Windows applications what HTML pages are to web browsers. FlowDocuments allow you to produce and display information in a document style in such a way that allows the documents content to re-shape itself depending on display space and options; just think web page and browser and your on the right track.
FixedDocuments on the other hand are to Windows applications what PDF's are to Adobe Reader. The emphasis of FixedDocuments is not in how the document is displayed but how it is printed.
With Windows Presentation Foundation a new document format called Xml Paper Specification (XPS) was introduced. This standard for describing document was combined with Open Packaging Convention (OPC) to produce a new, more open, approach to creating, printing, and storing documents.
This article describes how FlowDocuments can be converted to FixedDocuments (and XPS documents).
FlowDocuments vs FixedDocuments
FlowDocuments FlowDocuments are XAML files that describe in an XML language the content and format of a document. The syntax is very similar in nature to HTML pages. Here is an example:
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ColumnWidth="400" FontSize="14" FontFamily="Georgia"> <Paragraph> This is <Bold>my</Bold> paragraph. There are <Italic>many</Italic> like it but this one is <Bold>mine.</Bold> </Paragraph> <Paragraph> FlowDocuments are to Windows applications... </Paragraph> <Paragraph> FixedDocuments on the other hand are to Windows applications.... </Paragraph> </FlowDocument>
The above XML can be generated in a variety of ways and can also be stored in a variety of ways. For example, the FlowDocument could be produced with a XmlWriter or through a XSLT transformation, SqlServer query, and even produced through code as the example below shows.
FlowDocument flowDocument = new FlowDocument();
Paragraph para = new Paragraph();
para.Inlines.Add(new Run("This is "));
para.Inlines.Add(new Bold("my "));
para.Inlines.Add(new Run("paragraph. There are "));
para.Inlines.Add(new Italic("many "));
para.Inlines.Add(new Run("like it but this one is "));
para.Inlines.Add(new Bold("mine."));
In terms of storing the FlowDocument the document is simply text and so it can be stored to file, to database, stored to resource, and so on. However since a FlowDocument can be decribed with XAML the document can compiled into a more efficient BAML representation and stored within an assembly.
Remember that FlowDocuments are for displaying documents on screen in such a way as they adapt to the displays size and display options.
See FlowDocuments for more information.
FixedDocuments In contrast a FixedDocument is created following the guidelines described in the XPS specification, which is beyond the scope of this article. In brief a XPS/FixedDocument is a collection of XML files (that describe pages and content), Font files, and Image files that are all related in such a way as to describe the contents of the document.
The files that describe the document are all packaged up into a OPC paackage, which is a single file with a *.xps extension.
In terms of this article though FixedDocuments are designed for both printing the document or storing the document in a read-only state, similar like a PDF. The documents content is fixed because it doesn't adapt to suit display options.
See Writing a XPS Document for more information.
System.Printing.XpsDocumentWriter There are two classes responsible for converting a FlowDocument to a FixedDocument. These two classes are the System.Printing.XpsDocumentWriter class and the System.Windows.Documents.DocumentPaginator class.
The DocumentPaginator class (or a class that derives from it) is used to describe how the documents content is positioned and formatted on the FixedDocument.
For more information see Creating a custom DocumentPaginator
The XpsDocumentWriter class takes an instance of a DocumentPaginator class and uses it to write the documents content to XPS file. It does this in such a way that the resulting XPS file is fully compliant with the XPS specification.
What makes the conversion between FlowDocument and a FixedDocument work is the fact that a DocumentPaginator can be directly created from a FlowDocument. The FlowDocuments DocumentPaginator is passed to XpsDocumentWriter and the conversion is done.
You need to add a reference to System.Printing.dll before using System.Printing.XpsDocumentWriter.
Code Example You need to add references to the following before the code below will work:
* ReachFramework.dll - contains all the classes necessary for working with XPS files.
* WindowsBase.dll - contains all the classes necessary for working with OPC packages
* System.Printing.dll - contains the XpsDocumentWriter class.
* PresentationCore.dll and PresentationFramework.dll - the WPF classes (FlowDocument, etc)
The first step is to get a FlowDocument. There are a number of ways to do this and it all depending on the format and location of the FlowDocument.
If the FlowDocument is stored as a loose XAML file, usually specified with BuildOption Content, then you can use the XamlReader class to read it in.
FlowDocument document = null;
using (FileStream fs = File.Open("docAsContent.xaml", FileMode.Open))
{
document = XamlReader.Load(fs) as FlowDocument;
}
If the FlowDocument was compiled into a BAML, usually specified with BuildOption Page, then you can use the static Application.LoadComponent method to read it.
FlowDocument document = null;
document =
Application.LoadComponent(new Uri("docAsBaml.xaml",
UriKind.Relative)) as FlowDocument;
The next step, optional, is to display the generated XPS file. In order to this the DocumentViewer class is used. The following XAML shows a Window containing a DocumentViewer. In the code example that follows the generated XPS document will be displayed using this viewer.
<Window x:Class="WPFFlowDocToXPSFixedDoc.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<!-- DocumentViewer element is used to view Fixed Documents (XPS) -->
<DocumentViewer x:Name="xpsView" />
</Window>
Finally the conversion from FlowDocument to FixedDocument needs to be done. In order to do this you really need to think in terms of producing a XPS file. The process is really turn the FlowDocument to an XpsDocument and then turn the XpsDocument into a FixedDocument.
So FlowDocument to XpsDocument requires that a file is created, the XpsDocumentWriter then becomes a writer into that file. The content being written is the FlowDocuments DocumentPaginator.
Once the FlowDocument has been written to the XpsDocument a call to the XpsDocument.GetFixedDocumentSequence() is used to produce a FixedDocument and that is displayed in the DocumentViewer.
private void WriteXPS(FlowDocument flowDocument)
{
//generate temporary file name
string temp = System.IO.Path.GetTempFileName();
if (File.Exists(temp) == true)
File.Delete(temp);
//create a XPS document
XpsDocument xpsDoc = new XpsDocument(temp, FileAccess.ReadWrite);
//create a XPS document writer that writes to the XPS document
XpsDocumentWriter xpsWriter = XpsDocument.CreateXpsDocumentWriter(xpsDoc);
//write the flow document to the XPS document
// use the flow documents default DocumentPaginator to do that
xpsWriter.Write((flowDocument as IDocumentPaginatorSource).DocumentPaginator);
//display the XPS document in the DocumentViewer
// use the GetFixedDocumentSequence method to return a
// FixedDocument representation of the XPS file
xpsView.Document = xpsDoc.GetFixedDocumentSequence();
//close the XPS file
xpsDoc.Close();
}
[http://www.dsmyth.net/wiki/StudyNotes_WPFFlowDocToXPSFixedDoc.ashx]