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("-")) });



Typography Variants Superscript and Subscript Bug with .NET 4.0

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. 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章