Using FlowDocuments XAML to print XPS Documents. (Part 6)
Indroduction
This one is for you Linda and Cow-Killer.
Welcome to Part 6 of the Using FlowDocuments XAML to print XPS Documents series. Up until now it has been impossible to use this series to create an XPS document file or display the XAML text in a document viewer. It would be nice to be able to create a XAML template and easily insert text into the template using databinding. Here is my solution, hope to hear your feedback.
Creating a new method to Load Xaml Strings
This method simply takes a raw XAML string and loads it into a FlowDocument, you may have seen this before in previous samples.
public static IDocumentPaginatorSource RenderFlowDocumentTemplate(string templatePath,
Dictionary<string, string> parameters)
{
string rawXamlText = "";
using (StreamReader streamReader = File.OpenText(templatePath))
{
rawXamlText = streamReader.ReadToEnd();
}
rawXamlText = MergeParameters(parameters, rawXamlText);
FlowDocument document = XamlReader.Load(new XmlTextReader(new StringReader(rawXamlText))) as
FlowDocument;
return document;
}
The new parts of this method are the addition of a Dictionary of string key/value pairs and the MergeParameters method.
Merging Parameters
Since XAML is nothing more than a jazzed up XML file, we can use simple string replacements to replace items in our template with strings from our objects.
private static string MergeParameters(Dictionary<string, string> parameters, string template)
{
foreach (KeyValuePair<string, string> kvp in parameters)
{
template = template.Replace(string.Format("[{0}]", kvp.Key), kvp.Value);
}
return template;
}
Now we have a nearly completed solution to XAML template rendering, all that is left to do is create a template.
The new XAML Template
<FlowDocument xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml> <Paragraph FontFamily="Arial" Margin="20"> <TextBlock Text="[TestString]" FontSize="12"/> </Paragraph> </FlowDocument>
Notice the inclusion of [TestString], this is essentially the “databind” we will use in the string Key/Value pair dictionary.
Using the new Key/Value pair databinding
Dictionary<string, string> strings = new Dictionary<string,string>();
strings.Add("TestString", "Tester");
IDocumentPaginatorSource flowDocument =
XamlTemplatePrinter.RenderFlowDocumentTemplate(Path.Combine(Environment.CurrentDirectory,
"TestTemplate.xaml"), strings);
flowDocument.DocumentPaginator.PageSize = new Size(96 * 8.5, 96 * 11);
PrintDialog flowPrintDialog = XamlTemplatePrinter.GetPrintDialog();
if (flowPrintDialog == null)
return;
PrintQueue flowPrintQueue = flowPrintDialog.PrintQueue;
XamlTemplatePrinter.PrintFlowDocument(flowPrintQueue,
flowDocument.DocumentPaginator);
Conclusion
Thank you all for your comments and suggestions. Your questions and comments are fuel for the continued success of this blog. Please feel free to leave a comment or contact me if you have suggestions or questions.
Hi,
great code, do you have and example of how to display XPS document file or XAML text in a document viewer?
Also finding it difficult to pass Rich Text dynamically to flow document, any help appreciated.
The document viewer itself can display XAML pretty easily. Once you have created the XAML document, just pass it to the Document Viewer.
Can anybody please tell me where i can get xamltemplatePrinter class code?
Thanks in advance!
The XmlTemplatePrinter class was presented in this series. Several of the methods you will find in this series are STATIC and members of that class.
However, nowhere did I actually specify this accept in notes.
So is the XmlTemplatePrinter class the main class for the example (i.e. the namespace for the WPF application?) or is it a second user-defined class that simply hasn’t been displayed / mentioned explicitly?
Pretty much place all of the static methods into the XmlTemplatePrinter class.
I’m trying to create a Print Preview window and I’ve got a FlowDocument in a FlowDocumentScrollableViewer but the problem is one of the components I want to show as part of this document is already an XPS document.
Is it possible to merge an XPS document back into a FlowDocument? Or does it make more sense to simply create an XPS document of the original FlowDocument, merge it with the already existing XPS document. Then how do you show the user the merged XPS document prior to printing?
Thanks,
John
I would probably convert the XPS document to XAML then place it in my FlowDocument… Or view it in an XPS document viewer first.
Do you have a working sample of this project you could post?
Thank you~
I have working examples but all are under NDA. I could write up a sample app, but do not expect it soon… too many other projects on my plate.
Thanks a ton! Works great!
Now I have another question…I know I can’t leave your brilliance alone. We have a long running XPS document. Do you know of something that would visually indicate to the user that this page was taking a long time possibly using a background worker or popup?
Thanks,
Linda
Funny you would ask… I do have something like that. I will write up an article on the subject and post it later today.
Why not just use the FallbackValue Property on the Binding provide a value and design the FlowDocument in Kaxaml or XamlPad…
I am not certain what question you are trying to answer, but yup I did design some of my flowdocuments in XamlPad.