Microsoft Developer Network > 포럼 홈 > XML Paper Specification (XPS) > DocumentViewer / DocumentPaginator - only FixedDocument or FixedDocumentSequence???
질문하기질문하기
 

답변됨DocumentViewer / DocumentPaginator - only FixedDocument or FixedDocumentSequence???

  • 2009년 6월 8일 월요일 오전 8:33Jo0815 사용자 메달사용자 메달사용자 메달사용자 메달사용자 메달
     
    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 2009년 6월 8일 월요일 오전 8:36
    •  

답변

  • 2009년 6월 8일 월요일 오후 4:55Jo0815 사용자 메달사용자 메달사용자 메달사용자 메달사용자 메달
     답변됨코드 있음
    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
    • 답변으로 표시됨Jo0815 2009년 6월 8일 월요일 오후 4:58
    • 편집됨Jo0815 2009년 6월 9일 화요일 오전 6:21
    • 편집됨Jo0815 2009년 6월 9일 화요일 오전 6:21
    • 편집됨Jo0815 2009년 6월 9일 화요일 오전 6:22
    •  

모든 응답

  • 2009년 6월 8일 월요일 오후 4:55Jo0815 사용자 메달사용자 메달사용자 메달사용자 메달사용자 메달
     답변됨코드 있음
    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
    • 답변으로 표시됨Jo0815 2009년 6월 8일 월요일 오후 4:58
    • 편집됨Jo0815 2009년 6월 9일 화요일 오전 6:21
    • 편집됨Jo0815 2009년 6월 9일 화요일 오전 6:21
    • 편집됨Jo0815 2009년 6월 9일 화요일 오전 6:22
    •  
  • 2009년 11월 24일 화요일 오전 9:14Jo0815 사용자 메달사용자 메달사용자 메달사용자 메달사용자 메달
     코드 있음
    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??