Windows >
Software Development for Windows Client Forums
>
XML Paper Specification (XPS)
>
DocumentViewer / DocumentPaginator - only FixedDocument or FixedDocumentSequence???
DocumentViewer / DocumentPaginator - only FixedDocument or FixedDocumentSequence???
- Hello all,
when I assign my own DocumentPaginator to the DocumentViewer's Document I get an exception only FixedDocuments or FixedDocumentSequences are allowed.
I basicly want to modify pages of a XPS document (adding additional text/lines...) and show them in the DocumentViewer. I just thought I create my own DocumentPaginator (implementing also IDocumentPaginatorSource) and return the modified (document)pages in the method GetPage() so the pages getting created on-the-fly when the Document-Viewer needs to load and display them. But it seems this is not possible...
So the only way I currently see is to create a new XpsDocument in memory (either rendering using XpsSerializationManager/my own DocumentPaginator or via XpsDocumentWriter/SerializerWriterCollator) and then display this new created in the viewer. However I need to render *ALL* pages at once and when having documents with lots of pages this could take some seconds (f.e. in my case a document needs 7-10s) before showing up in the viewer then... ofcourse not really a good way...
Are there any better ways to display Visuals (-> DocumentPages) in the DocumentViewer and render pages on the fly when they get displayed??
Can anyone of Microsoft bring some light into this why it's not possible to assign an own DocumentPaginator to the DocumentViewer providing own DocumentPages???
any ideas are welcome...
regards from Germany,
Jo- Edited byJo0815 Monday, June 08, 2009 8:36 AM
Answers
- Ok, guess I found a good solution which works for Visuals, though the text of the visuals can't be selected, but I guess myself when using a Canvas-object instead of the VisualHost this would work also, but as my internal renderer using visuals that's Ok for me right now...
The trick is to host the "overlay visual" of a page in a UIElement and then add it to the DocumentPage (Visual -> FixedPage) in the GetPageCompleted-event of the FixedDocumentSequences DocumentPaginator... that way it's not needed to create the whole document at once and the pages (plus their overlays) getting loaded when needed... :)
Here's a little sample code for it, maybe it's also useful for others... It just adds text "Page #XX" on bottom to every page of the XPS document.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Controls; using System.Windows.Xps.Packaging; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Forms; using System.IO; using System.Windows; namespace XpsViewer { public partial class Form1 : Form { private DocumentViewer fDocViewer; public Form1() { InitializeComponent(); Initialize(); } private void Initialize() { // Create a DocumentViewer and add it to ElementHost fDocViewer = new DocumentViewer(); elementHost.Child = fDocViewer; // Load a XpsDocument XpsDocument xpsDocument = new XpsDocument(@"D:\Temp\xDOC_Testdokument.xps", FileAccess.ReadWrite); // Get the FixedDocumentSequence FixedDocumentSequence fseq = xpsDocument.GetFixedDocumentSequence(); // and set the OnGetPageComplete-Event fseq.DocumentPaginator.GetPageCompleted += OnGetPageComplete; // assign the document to the DocumentViewer fDocViewer.Document = fseq; // close Document xpsDocument.Close(); } private void OnGetPageComplete(object sender, GetPageCompletedEventArgs e) { // Leave here when canccelled or an error ocurred if (e.Cancelled || (e.Error != null)) { return; } // Get the fixed page currently displayed FixedPage page = (FixedPage)e.DocumentPage.Visual; // Create a new visual host... toDO: Maybe needs a check here if our VisualHost is already added to the page??? VisualHost host = new VisualHost(); // ...and add our test-visual host.AddVisual(CreateVisual(page.Width, page.Height, string.Format("page #{0}", e.PageNumber + 1))); // add the visual host to the fixed page page.Children.Add(host); } public Visual CreateVisual(double width, double height, string message) { // create a drawing visual DrawingVisual visual = new DrawingVisual(); using (DrawingContext ctx = visual.RenderOpen()) { // just draw some text FormattedText text = new FormattedText(message, System.Globalization.CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight, new Typeface("Tahoma"), 12 * 1.5, new SolidColorBrush(Color.FromRgb(0, 0, 0)) ); ctx.DrawText(text, new System.Windows.Point(100, height - 125)); } return visual; } } }
and here's the class for the VisualHost:
public class VisualHost : UIElement { private List<Visual> fVisuals; public VisualHost() { fVisuals = new List<Visual>(); } protected override Visual GetVisualChild(int index) { return fVisuals[index]; } protected override int VisualChildrenCount { get { return fVisuals.Count; } } public void AddVisual(Visual visual) { fVisuals.Add(visual); base.AddVisualChild(visual); } public void RemoveVisual(Visual visual) { fVisuals.Remove(visual); base.RemoveVisualChild(visual); } }
hope you like it and maybe it's useful...
regards from Germany
Jo
All Replies
- Ok, guess I found a good solution which works for Visuals, though the text of the visuals can't be selected, but I guess myself when using a Canvas-object instead of the VisualHost this would work also, but as my internal renderer using visuals that's Ok for me right now...
The trick is to host the "overlay visual" of a page in a UIElement and then add it to the DocumentPage (Visual -> FixedPage) in the GetPageCompleted-event of the FixedDocumentSequences DocumentPaginator... that way it's not needed to create the whole document at once and the pages (plus their overlays) getting loaded when needed... :)
Here's a little sample code for it, maybe it's also useful for others... It just adds text "Page #XX" on bottom to every page of the XPS document.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Controls; using System.Windows.Xps.Packaging; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Forms; using System.IO; using System.Windows; namespace XpsViewer { public partial class Form1 : Form { private DocumentViewer fDocViewer; public Form1() { InitializeComponent(); Initialize(); } private void Initialize() { // Create a DocumentViewer and add it to ElementHost fDocViewer = new DocumentViewer(); elementHost.Child = fDocViewer; // Load a XpsDocument XpsDocument xpsDocument = new XpsDocument(@"D:\Temp\xDOC_Testdokument.xps", FileAccess.ReadWrite); // Get the FixedDocumentSequence FixedDocumentSequence fseq = xpsDocument.GetFixedDocumentSequence(); // and set the OnGetPageComplete-Event fseq.DocumentPaginator.GetPageCompleted += OnGetPageComplete; // assign the document to the DocumentViewer fDocViewer.Document = fseq; // close Document xpsDocument.Close(); } private void OnGetPageComplete(object sender, GetPageCompletedEventArgs e) { // Leave here when canccelled or an error ocurred if (e.Cancelled || (e.Error != null)) { return; } // Get the fixed page currently displayed FixedPage page = (FixedPage)e.DocumentPage.Visual; // Create a new visual host... toDO: Maybe needs a check here if our VisualHost is already added to the page??? VisualHost host = new VisualHost(); // ...and add our test-visual host.AddVisual(CreateVisual(page.Width, page.Height, string.Format("page #{0}", e.PageNumber + 1))); // add the visual host to the fixed page page.Children.Add(host); } public Visual CreateVisual(double width, double height, string message) { // create a drawing visual DrawingVisual visual = new DrawingVisual(); using (DrawingContext ctx = visual.RenderOpen()) { // just draw some text FormattedText text = new FormattedText(message, System.Globalization.CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight, new Typeface("Tahoma"), 12 * 1.5, new SolidColorBrush(Color.FromRgb(0, 0, 0)) ); ctx.DrawText(text, new System.Windows.Point(100, height - 125)); } return visual; } } }
and here's the class for the VisualHost:
public class VisualHost : UIElement { private List<Visual> fVisuals; public VisualHost() { fVisuals = new List<Visual>(); } protected override Visual GetVisualChild(int index) { return fVisuals[index]; } protected override int VisualChildrenCount { get { return fVisuals.Count; } } public void AddVisual(Visual visual) { fVisuals.Add(visual); base.AddVisualChild(visual); } public void RemoveVisual(Visual visual) { fVisuals.Remove(visual); base.RemoveVisualChild(visual); } }
hope you like it and maybe it's useful...
regards from Germany
Jo


