MSDN >
論壇首頁
>
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- 已編輯Jo0815 Monday, 8 June, 2009 8:36
解答
- 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
所有回覆
- 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 - When I try to add the visual host on first position to get some kind of "watermark" which is behind the original document,
private void OnGetPageComplete(object sender, GetPageCompletedEventArgs e) { ... // set background transparent of original document page.Background = System.Windows.Media.Brushes.Transparent; // insert the visual host to the page on first position page.Children.Insert(0, host); }
then it displays the text behind, but I'll get the following ArgumentNullException as soon as I move mouse over the documentviewer-control:
System.ArgumentNullException wurde nicht behandelt.
Message="Der Wert darf nicht NULL sein.\r\nParametername: descendant"
Source="PresentationCore"
ParamName="descendant"
StackTrace:
bei System.Windows.Media.Visual.TransformToDescendant(Visual descendant)
bei System.Windows.Documents.FixedTextView._SnapToText(Point point)
bei System.Windows.Documents.FixedTextView.GetTextPositionFromPoint(Point point, Boolean snapToText)
bei MS.Internal.Documents.TextViewBase.System.Windows.Documents.ITextView.GetTextPositionFromPoint(Point point, Boolean snapToText)
bei System.Windows.Documents.DocumentSequenceTextView.GetTextPositionFromPoint(Point point, Boolean snapToText)
bei MS.Internal.Documents.TextViewBase.System.Windows.Documents.ITextView.GetTextPositionFromPoint(Point point, Boolean snapToText)
bei MS.Internal.Documents.DocumentPageTextView.GetTextPositionFromPoint(Point point, Boolean snapToText)
bei MS.Internal.Documents.MultiPageTextView.GetTextPositionFromPoint(Point point, Boolean snapToText)
bei MS.Internal.Documents.TextViewBase.System.Windows.Documents.ITextView.GetTextPositionFromPoint(Point point, Boolean snapToText)
bei System.Windows.Documents.TextEditorMouse.IsPointWithinInteractiveArea(TextEditor textEditor, Point point)
bei System.Windows.Documents.TextEditorMouse.OnQueryCursor(Object sender, QueryCursorEventArgs e)
bei System.Windows.Input.QueryCursorEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
bei System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
bei System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
bei System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
bei System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
bei System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
bei System.Windows.Input.InputManager.ProcessStagingArea()
bei System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
bei System.Windows.Input.MouseDevice.UpdateCursorPrivate()
bei System.Windows.Input.MouseDevice.PostProcessInput(Object sender, ProcessInputEventArgs e)
bei System.Windows.Input.InputManager.ProcessStagingArea()
bei System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
bei System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
bei System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
bei System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
bei System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
bei MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
bei MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
bei System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
bei System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
bei System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
bei System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
bei MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
bei System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
bei System.Windows.Forms.Application.Run(Form mainForm)
anyone got a clue why adding the visualhost works, but not when inserting on first position??

