FlowDocument

From
Jump to: navigation, search

Overview

A document model that can be composed using flow layout rules applied to various content elements or content containers and later saved as PDF document according to the given page size, PDF standard and other settings. It can be also saved as an XML template and loaded from it using routines implemented as instance and static methods.

The FlowDocument supports styling for its elements and itself using style objects which can be registered using its StyleManager along with the matching expressions/selectors(document level styling). Alternatively, instance properties can be used for changing particular element's appearance (element level styling).

Resource management

All necessary resources such as images, FixedContent objects, fonts should be registered in a special repository class ResourceManager in order to be used by any of the ContentElement objects composing flow document's content. One ResourceManager instance can serve multiple FlowDocument instances as it's independent from the flow document model and is used only when the document is being saved to PDF. It's primary role is to map resource ids assigned by the user to the actual data needed to generate PDF objects, this way one binary object such as image can be used many times within the PDF document by its reference(id) and stored only once reducing the final document's size.

Page size

In Flow layout API there's no page size setting, it gets set during the save process and in this moment the outermost container element which is FlowDocument object receives the requred sizing info to cut the content into pages. All pages generated this way will have the same size, and it's assumed that style set used for all elements on all pages will be the same. If you need to alter the size or styles used by a particular page read the article below.

Change page size and styles on the fly

FlowDocument uses fixed page size and single style set by default and every page becomes sized and styled using these same settings. Sometimes where is a need to change the style (e.g. generate a booklet with page numbers placed on the left for odd pages and on the right for even pages). Page size may also require a change in some cases. These settings can be changed for a particular page or a range of pages by providing a handler for NewPage event defined by FlowDocument class.

Note: only elements which are being created on a particular page will be affected by style or page size change. If element spans across multiple pages, then its style will be defined by the page where it has been created.

Consider the code below:

using (Stream outputStream = File.Create("custom_page_settings.pdf"))
{
    FlowDocument document = new FlowDocument() { Margin = new Thickness(5) };
    
    // register style for page header using id selector
    document.StyleManager.RegisterStyle("#header", new Style(){ Align = Align.Left, Background = RgbColors.LightGray });
    
    // define new page handler
    document.NewPage += (args) =>
        {
            // redefine style for pageheader and page size for pages with indices 1, 3, 5 etc.
            if ((args.Context.CurrentPage & 0x1) != 0)
            {
                args.OverridingStyleManager.RegisterStyle("#header",new Style()
                    {
                        Align = Align.Right, Background = RgbColors.Gray
                    });
    
                args.PageBoundary = new PageBoundary(new Boundary(0, 0, 300, 500));
            }
        };
    
    // define page header, display current page index
    document.PageHeader.Id = "header";
    document.PageHeader.Add(new TextBlock((ctx)=>string.Format("Page {0}",ctx.CurrentPage+1)));
    
    // add content
    document.Add(new TextBlock("Header on this page has left-aligned page " +
        "number and page size 200pt x 500pt"));
    document.Add(new PageBreak());
    document.Add(new TextBlock("Header on this page has right-aligned page number" +
        " and page size 300pt x 500pt"));
    
    // save document
    document.Write(outputStream, new ResourceManager(), new PageBoundary(new Boundary(0,0,200,500)));
}
 


This code redefines page header style and page size for even pages and produces the document that looks as follows:


Change page size and style on the fly