Answered FlowDocument rendering questions

  • 19. ledna 2006 5:38
    Moderátor
     
     

    If I want to render a FlowDocument to an irregular area what are the best approaches?  I would like to be able to render a flow document to a series of rectangles that are not arranged in Y linear order.  Basically, allow free-form page layout with content flowing from one place on the page to the next.  Can this be done with any existing control?  While FlowDocument supports columns and floaters and such to do simple page layout, is that all there is in this version?  Is there a way to at least have different page orientations within the same document?  For example if I have a large table and want to use landscape in the middle of a document that is mostly portrait?  Can I use a DocumentPageView with a collection of DocumentPage objects to layout the pages in various ways?

    On a related note, I want to render multiple pages to the screen at one time.  Can I do this with one DocuemntPageView, one per page, or what?  Why would it have a collection of DocumentPage objects if it only displays one page?

    The documentation is a bit thin on this.  I will check for samples when it is earlier in the day.  Any pointers, or answers welcome.

     

Všechny reakce

  • 25. ledna 2006 1:56
     
     

    Hi Micheal, congratulations on the MVP.

    To render a FlowDocument as a series of 'identically sized rectangles' not arranged in Y linear order'; you can use multiple DocumentPageViews in a SinglePageViewer style

    see http://fortes.com/2005/10/11/customizing-singlepageviewer-part1

    Alternatively you can create your own control that manages a set of DocumentPageViews whos positions you manage.

    Unfortunately FlowDocument only supports a single page size, any attempt to change an individual page's size will result in all other pages resizing.

    Finally you can't directly render the same page several times using a DocumentPageView. The primary scenario for DocumentPageView is to view multiple pages, but not multiple copies of the same page at the same time. Part of the limitation is handling the case where a UIElement is embedded in two views. Hit testing and rendering (a Visual can only be in one place at a time) issues become hairy.

    As a workaround you can subclass DocumentPageView to show a non interactive duplicate of a page. Below is a very basic sample of this using a VisualBrush rendered on a rectangle.

    namespace DPVSample {
        using System;
        using System.Windows;
        using System.Windows.Media;
        using System.Windows.Controls;
        using System.Windows.Controls.Primitives;
        using System.Windows.Documents;
       
        public class EntryPoint {
            [STAThread]
            public static void Main() {
                Application app = new Application();
                app.Startup += OnStartup;
                app.Run();
            }
           
            static void OnStartup(object sender, StartupEventArgs eventArgs) {
                Window w = new Window();
               
                UniformGrid panel = new UniformGrid();           
               
                FlowDocument fd = new FlowDocument();
                fd.Blocks.Add(new Paragraph(new Run("Page 1")));
               
                Paragraph paragraph2 = new Paragraph(new Run("Page 2"));
                paragraph2.BreakPageBefore = true;
                fd.Blocks.Add(paragraph2);
               
                Paragraph paragraph3 = new Paragraph(new Run("Page 3"));
                paragraph3.BreakPageBefore = true;
                fd.Blocks.Add(paragraph3);
               
                DocumentPaginator paginator = ((IDocumentPaginatorSource)fd).DocumentPaginator;
               
                AddPageView(panel, paginator, 0);
                AddPageView(panel, paginator, 1);
                AddPageView(panel, paginator, 0);
                AddPageView(panel, paginator, 2);
                
                w.Content = panel;
               
                w.Show();
            }
           
            static void AddPageView(Panel panel, DocumentPaginator paginator, int pageNumber) {
                DocumentPageView dpv = new DuplicateDocumentPageView();
                dpv.Stretch = Stretch.None;
                dpv.DocumentPaginator = paginator;
                dpv.PageNumber=pageNumber;
                panel.Children.Add(dpv);
            }
           
            public class DuplicateDocumentPageView: DocumentPageView {
                public DuplicateDocumentPageView() {
                    PageConnected += PageConnectedHandler;
                    PageDisconnected += PageDisconnectedHandler;
                }               
               
                VisualBrush brush = new VisualBrush();
                protected override void OnRender(DrawingContext drawingContext) {
                    //base.OnRender(drawingContext);
                    drawingContext.DrawRectangle(brush, null, new Rect(new Point(0, 0), RenderSize));
                }

                void PageConnectedHandler(object sender, EventArgs eventArgs) {
                    brush.Visual = DocumentPage.Visual;
                }
               
                void PageDisconnectedHandler(object sender, EventArgs eventArgs) {
                    brush.Visual = null;
                }
            }
        }
    }
     

    -- Ifeanyi Echeruo [MSFT]
    This posting is provided "AS IS" with no warranties, and confers no rights.
       

  • 25. ledna 2006 2:16
    Moderátor
     
     

    So, I take it the following are true:

    1) I can practically only have one set of pages all the same size/orientation.  Which I could place as I choose in a larger element.

    2) If I want multiple text streams I need to use Figure/Floater type elements that are within the page sequence, rather than having multiple page sequences interlieved.

    3) FlowDocument is currently better suited to long documents (like word) rather than page layout (like quark).

    Is there any control that currently supports text flow from one rectangle to another?  Can I have text flow from one Floater to another when the contents are larger than the area allocated?  For example can I have a side bar that flows from one page to another?

  • 25. ledna 2006 19:44
     
     Odpovědět

    All three statements are correct.

    There is no control that supports text flowing from one rect to another. It is possible to implement such a control with our core text API's. Then one could embed the control as a UIElement in Floaters.

    System.Windows.Media.TextFormatter has methods to format a line of text obtained from a TextSource (abstract) and return a TextLine that has layout information and render methods.

    So you can format lines until you run out of space in a UIElement rect and just move on to the 'next' UIElement rect.

    This posting is provided "AS IS" with no warranties, and confers no rights.

  • 25. ledna 2006 20:53
    Moderátor
     
     
    Thanks for the follow-up.  So what I want to do is technically possible, but currently hard.  I found thin docs on the TextFormatter and TextLine classes, and an example for TextFormatter.  I will probably have more detailed questions if and when I dig into this in detail.  I would like to get into some of this, but I do not know if it will make the cut for the first set of features for my application.  This at least gets me started, and lets me know that it is not already there, and will take a fair amount of digging to work out.  Learning new stuff at least is fun.
  • 25. ledna 2006 22:14
    Moderátor
     
     Odpovědět
    Yes, you're spot on with your assertion that it's possible, but hard. Ultimately, this first version of Avalon isn't set up for out-of-the-box complex Magazine-style (Quark-built) flowing layouts.