Flow Document in WPF

<FlowDocument
  xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’
  xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’>
  <Paragraph>The quick <Bold>brown fox</Bold> jumps over the lazy dog.
</Paragraph>
</FlowDocument>

基本概念:

Flow document是Collections of blocks.Block是继承System.Windows.Documents.Block Class;

 重要的BlockType:

Block Description
Paragraph段落 Contains (potentially richly formatted) text.
List列表 Contains lists of various kinds (numbered, bulleted, and so on).
Table表格 Contains tables similar to those in Microsoft Word or HTML.
BlockUIContainer可以包括多个UI Elements Contains various UI elements that are made part of the overall flow.
Section一组Block Contains a group of other blocks. Sections are handy for applying common attributes to a group of blocks, such as the same font attributes to multiple paragraphs

XAML:
<FlowDocument>
  <Paragraph>Hello World!</Paragraph>
</FlowDocument>
c#代码:
FlowDocument doc = new FlowDocument();
Paragraph para = new Paragraph();
para.Inlines.Add(“Hello World!”);
doc.Blocks.Add(para);
Figue,Floater,LineBreak;

<Paragraph>
  <Figure Width=”200”>
    <BlockUIContainer>
      <Image Source=”Pictures\Humpback Whale.jpg” />
    </BlockUIContainer>
    <Paragraph Foreground=”Blue” FontFamily=”Consolas”>
        The Whale</Paragraph>
  </Figure>
  The quick brown fox jumps over the lazy dog. The quick brown...
</Paragraph>

显示FlowDocument的控件:FlowDocumentReader (支持分页,预览,缩放,查找等功能),FlowDocumentScrollViewer,


<FlowDocument IsOptimalParagraphEnabled=”true” 
    IsHyphenationEnabled=”true”>
IsOptimalParagraphEnabled(平均分配段落之间的空格):distribute white space as evenly as possible within a given paragraph, resulting in a much improved reading experience
IsHyphenationEnabled=”true” (断字功能)

导出功能/导入其他格式(RTF,XAML等)文件的功能:

doc = new FlowDocument();

var content = new TextRange(doc.ContentStart, doc.ContentEnd);
            if (content.CanSave(DataFormats.Rtf))
            {
                using (var stream = new FileStream(@"c:\temp\text.rtf", FileMode.Create))
                {
                    content.Save(stream, DataFormats.Rtf);                    
                }
            }

            FlowDocument doc2 =new FlowDocument();
            var content2 = new TextRange(doc2.ContentStart, doc2.ContentEnd);

            if (content2.CanLoad(DataFormats.Rtf))
            {
                using (var stream = new FileStream(@"c:\temp\text.rtf", FileMode.Open))
                {
                    content2.Load(stream, DataFormats.Rtf);
                }
            }

打印文档:

PrintDialog printDialog = new PrintDialog(); 
                if (printDialog.ShowDialog() == true) {

                FlowDocument fd = new FlowDocument();
                    var stream = new FileStream(@"c:\temp\text.rtf", FileMode.Open);
                    
                TextRange tr = new TextRange(fd.ContentStart, fd.ContentEnd);

                tr.Load(stream, DataFormats.Rtf);

                stream.Close();
                fd.ColumnWidth = printDialog.PrintableAreaWidth;                
                                   
                printDialog.PrintDocument(((IDocumentPaginatorSource)fd).DocumentPaginator, "myReport");

            }


如果需要自定义的Header/Footer,则需要实现DocumentPaginator接口:

public class HeaderedFlowDocumentPaginator : DocumentPaginator
    {
        private DocumentPaginator flowDocumentpaginator;


        public HeaderedFlowDocumentPaginator(FlowDocument document)
        {
            flowDocumentpaginator = ((IDocumentPaginatorSource)document).DocumentPaginator;
        }


        public override bool IsPageCountValid
        {
            get { return flowDocumentpaginator.IsPageCountValid; }
        }


        public override int PageCount
        {
            get { return flowDocumentpaginator.PageCount; }
        }


        public override Size PageSize
        {
            get { return flowDocumentpaginator.PageSize; }
            set { flowDocumentpaginator.PageSize = value; }
        }


        public override IDocumentPaginatorSource Source
        {
            get { return flowDocumentpaginator.Source; }
        }


        Rect Move(Rect rect,Size m_Margin)
        {
            if (rect.IsEmpty)
            {
                return rect;
            }
            else
            {
                return new Rect(rect.Left + m_Margin.Width, rect.Top + m_Margin.Height,
                                rect.Width, rect.Height);
            }
        }
        
public override DocumentPage GetPage(int pageNumber)
        {
            DocumentPage page = null;
            if (this != flowDocumentpaginator)
            {
                page = flowDocumentpaginator.GetPage(pageNumber);
            }
            else
            {
                page = new DocumentPage(new ContainerVisual());
            }
            // Create a wrapper visual for transformation and add extras 
            ContainerVisual newpage = new ContainerVisual();
            DrawingVisual title = new DrawingVisual();


            using (DrawingContext ctx = title.RenderOpen())
            {
                ctx.DrawRectangle(Brushes.White, null, new Rect(page.Size));
                
                    var m_Typeface = new Typeface("Arial");
                
                FormattedText text = new FormattedText("DNV Test\r\nVerIT-V test\r\n\r\ntwo stroke inline" + (pageNumber + 1),
                    System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                    m_Typeface, 14, Brushes.Black);
                ctx.DrawText(text, new Point(0, 0)); // 1/4 inch above page content 

                FormattedText text2 = new FormattedText("Nauticus Crankshaft Fatigue (beta)\r\nVersion 10.0\r\nBy DNV Software" + (pageNumber + 1).ToString(), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, m_Typeface, 14, Brushes.Black);
                ctx.DrawText(text2, new Point(page.Size.Width - 150, 10));
                var pic = new BitmapImage(new Uri("pack://application:,,,/Icon/dnv_logo.jpg", UriKind.RelativeOrAbsolute));
               ctx.DrawImage(pic, new Rect(new Point(page.Size.Width / 2, 10), new Point(page.Size.Width / 2 + pic.Width, pic.Height + 10)));

            }

            ContainerVisual smallerPage = new ContainerVisual();
            try
            {
                newpage.Children.Add(title);
                smallerPage.Children.Add(page.Visual);
                smallerPage.Transform = new MatrixTransform(0.85, 0, 0, 0.85,
                    0.05 * page.ContentBox.Width, 0.05 * page.ContentBox.Height);
                newpage.Children.Add(smallerPage);
                var m_Margin = new Size(96, 48);
                newpage.Transform = new TranslateTransform(m_Margin.Width, m_Margin.Height);
                var m_PageSize = new Size(page.Size.Width, page.Size.Height);
                return new DocumentPage(newpage, m_PageSize, Move(page.BleedBox, m_Margin), Move(page.ContentBox, m_Margin));
            }
            catch (Exception e)
            {
                return null;
            }
        } 


    }


常见的Code(创建table,支持希腊字母,Subscript,ect...):

public static void WriteText(FlowDocument flowDocument, string text, bool isBold)
        {
            var para = new Paragraph();
            Bold b = new Bold();
            b.Inlines.Add(text);
            if (isBold)
            {
                para.Inlines.Add(b);
            }
            else
            {
                para.Inlines.Add(text);
            }
            flowDocument.Blocks.Add(para);
        }

public static TableRow AddTableRow(Table table, string[] rowData)
        {
            var currentRow = new TableRow();
            table.RowGroups[0].Rows.Add(currentRow);


            foreach (var row in rowData)
            {
                currentRow.Cells.Add(new TableCell(new Paragraph(new Run(row))));
            }
            return currentRow;
        }


        public static TableRow AddTableRow(Table table, Paragraph[] rowData)
        {
            var currentRow = new TableRow();
            table.RowGroups[0].Rows.Add(currentRow);


            foreach (var row in rowData)
            {
                currentRow.Cells.Add(new TableCell(row));
            }
            return currentRow;
        }


        public static Paragraph AddTypographySymbol(string firstPart, string secondPart, FontVariants secondPartVariants)
        {
            var para = new Paragraph();
            var run = new Run(firstPart);
            para.Inlines.Add(run);
            run = new Run(secondPart);
            run.FontFamily = new System.Windows.Media.FontFamily("Palatino Linotype");
            run.Typography.Variants = secondPartVariants;
            para.Inlines.Add(run);
            return para;
        }


        public static Paragraph AddTypographySymbol(string firstPart, string secondPart, FontVariants secondPartVariants, string thirdPart)
        {
            var para = new Paragraph();
            var run = new Run(firstPart);
            para.Inlines.Add(run);
            run = new Run(secondPart);
            run.FontFamily = new System.Windows.Media.FontFamily("Palatino Linotype");
            run.Typography.Variants = secondPartVariants;
            para.Inlines.Add(run);
            run = new Run(thirdPart);
            para.Inlines.Add(run);
            return para;
        }


var inputTable = new Table();

          doc.Blocks.Add(inputTable);


                inputTable.Columns.Add(new TableColumn());
                inputTable.Columns.Add(new TableColumn());
                inputTable.Columns.Add(new TableColumn());


                // Create and add an empty TableRowGroup to hold the table's Rows.
                inputTable.RowGroups.Add(new TableRowGroup());
                var currentRow = FlowDocumentReportWapper.AddTableRow(inputTable, new[] { "Input parameter", String.Empty, string.Empty });


                // Global formatting for the title row.
                currentRow.FontStyle = FontStyles.Italic;


FlowDocumentReportWapper.AddTableRow(inputTable, new[] { FlowDocumentReportWapper.AddTypographySymbol("Outer diameter,d", "o", FontVariants.Subscript, ":"), new Paragraph(new Run(CommonData.GetFormattedValue(Dout))), new Paragraph(new Run("mm")) });


FlowDocumentReportWapper.AddTableRow(outputTable, new[] { FlowDocumentReportWapper.AddTypographySymbol("SCF, torsion α", "t", FontVariants.Subscript, ":"), new Paragraph(new Run(CommonData.GetFormattedValue(Alphat, 3))), new Paragraph(new Run("-")) });



There is an odd bug that happens when using Typography Variants of Superscript and Subscript, which causes the Variant to not be implemented. It only happens when a number is in the Run with the attached property set. E.g.:

     <TextBlock FontFamily="Palatino Linotype" FontSize="30">
         x<Run Typography.Variants="Superscript">2</Run>
         x<Run Typography.Variants="Superscript">1234</Run>
         x<Run Typography.Variants="Superscript">A</Run>
         x<Run Typography.Variants="Superscript">2A</Run>
     </TextBlock>

The first 2 examples will fail, but the second 2 will be OK.

This is a known issue of WPF 4.0, and unfortunately, we did not get any workaround until now. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值