流文档概述

流文档旨在优化查看和可读性。 流文档不是设置为一个预定义布局,而是根据运行时变量(例如窗口大小、设备分辨率和可选用户首选项)动态调整和重排其内容。 此外,流文档还提供高级文档功能,如分页和列。 本主题概述了流文档以及如何创建它们。

什么是流文档

流文档旨在根据窗口大小、设备分辨率和其他环境变量“重排内容”。 此外,流文档具有许多内置功能,包括搜索、查看模式,可优化可读性,以及更改字体大小和外观的能力。 当易于阅读是主要文档使用方案时,最好使用流文档。 相比之下,固定文档设计用于静态展示。 当源内容的保真度至关重要时,固定文档非常有用。 有关不同类型的文档的详细信息,请参阅 WPF 中的文档

下图显示了在不同大小的多个窗口中查看的示例流文档。 随着显示区域的变化,内容重排以充分利用可用空间。

流文档内容重排

如上图所示,流内容可以包含多个组件,包括段落、列表、图像等。 这些组件对应于过程代码中的标记和对象中的元素。 我们将在本概述的 “流相关类” 部分中详细介绍这些类。 目前,下面是一个简单的代码示例,它创建一个包含一些粗体文本和列表的段落的流文档。

<!-- This simple flow document includes a paragraph with some
     bold text in it and a list. -->
<FlowDocumentReader xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <FlowDocument>
    <Paragraph>
      <Bold>Some bold text in the paragraph.</Bold>
      Some text that is not bold.
    </Paragraph>

    <List>
      <ListItem>
        <Paragraph>ListItem 1</Paragraph>
      </ListItem>
      <ListItem>
        <Paragraph>ListItem 2</Paragraph>
      </ListItem>
      <ListItem>
        <Paragraph>ListItem 3</Paragraph>
      </ListItem>
    </List>

  </FlowDocument>
</FlowDocumentReader>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
    public partial class SimpleFlowExample : Page
    {
        public SimpleFlowExample()
        {

            Paragraph myParagraph = new Paragraph();

            // Add some Bold text to the paragraph
            myParagraph.Inlines.Add(new Bold(new Run("Some bold text in the paragraph.")));

            // Add some plain text to the paragraph
            myParagraph.Inlines.Add(new Run(" Some text that is not bold."));

            // Create a List and populate with three list items.
            List myList = new List();

            // First create paragraphs to go into the list item.
            Paragraph paragraphListItem1 = new Paragraph(new Run("ListItem 1"));
            Paragraph paragraphListItem2 = new Paragraph(new Run("ListItem 2"));
            Paragraph paragraphListItem3 = new Paragraph(new Run("ListItem 3"));

            // Add ListItems with paragraphs in them.
            myList.ListItems.Add(new ListItem(paragraphListItem1));
            myList.ListItems.Add(new ListItem(paragraphListItem2));
            myList.ListItems.Add(new ListItem(paragraphListItem3));

            // Create a FlowDocument with the paragraph and list.
            FlowDocument myFlowDocument = new FlowDocument();
            myFlowDocument.Blocks.Add(myParagraph);
            myFlowDocument.Blocks.Add(myList);

            // Add the FlowDocument to a FlowDocumentReader Control
            FlowDocumentReader myFlowDocumentReader = new FlowDocumentReader();
            myFlowDocumentReader.Document = myFlowDocument;

            this.Content = myFlowDocumentReader;
        }
    }
}

Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents

Namespace SDKSample
    Partial Public Class SimpleFlowExample
        Inherits Page
        Public Sub New()

            Dim myParagraph As New Paragraph()

            ' Add some Bold text to the paragraph
            myParagraph.Inlines.Add(New Bold(New Run("Some bold text in the paragraph.")))

            ' Add some plain text to the paragraph
            myParagraph.Inlines.Add(New Run(" Some text that is not bold."))

            ' Create a List and populate with three list items.
            Dim myList As New List()

            ' First create paragraphs to go into the list item.
            Dim paragraphListItem1 As New Paragraph(New Run("ListItem 1"))
            Dim paragraphListItem2 As New Paragraph(New Run("ListItem 2"))
            Dim paragraphListItem3 As New Paragraph(New Run("ListItem 3"))

            ' Add ListItems with paragraphs in them.
            myList.ListItems.Add(New ListItem(paragraphListItem1))
            myList.ListItems.Add(New ListItem(paragraphListItem2))
            myList.ListItems.Add(New ListItem(paragraphListItem3))

            ' Create a FlowDocument with the paragraph and list.
            Dim myFlowDocument As New FlowDocument()
            myFlowDocument.Blocks.Add(myParagraph)
            myFlowDocument.Blocks.Add(myList)

            ' Add the FlowDocument to a FlowDocumentReader Control
            Dim myFlowDocumentReader As New FlowDocumentReader()
            myFlowDocumentReader.Document = myFlowDocument

            Me.Content = myFlowDocumentReader
        End Sub
    End Class
End Namespace

下图显示了此代码片段的外观。

屏幕截图:已渲染的 FlowDocument 示例

在此示例中,该 FlowDocumentReader 控件用于托管流内容。 有关流内容托管控件的详细信息,请参阅 流文档类型ParagraphListListItemBold元素用于根据其在标记中的顺序来控制内容格式。 例如,元素 Bold 仅跨越段落中部分文本;因此,只有该部分文本是粗体。 如果已使用 HTML,则你对此很熟悉。

如上图中突出显示的那样,流文档中内置了几个功能:

  • 搜索:允许用户对整个文档执行全文搜索。

  • 查看模式:用户可以选择其首选的查看模式,包括单页(一次页面)查看模式、一次两页(书籍阅读格式)查看模式,以及连续滚动(无底)查看模式。 有关这些查看模式的详细信息,请参阅 FlowDocumentReaderViewingMode

  • 页面导航控件:如果文档的查看模式使用页面,页面导航控件包括一个按钮,用于跳转到下一页(向下箭头)或上一页(向上箭头),以及当前页号和总页数的指示器。 还可以使用键盘箭头键完成翻转页面。

  • 缩放:缩放控件使用户能够分别单击加号或减号按钮来增加或减少缩放级别。 缩放控件还包括用于调整缩放级别的滑块。 有关详细信息,请参阅 Zoom

可以根据用于托管流内容的控件修改这些功能。 下一部分介绍不同的控件。

流文档类型

显示流文档内容及其显示方式取决于用于托管流内容的对象。 有四个控件支持查看流内容: FlowDocumentReaderFlowDocumentPageViewerRichTextBoxFlowDocumentScrollViewer。 下面简要介绍了这些控件。

注释

FlowDocument 是直接托管流内容所必需的,因此所有这些查看控件都使用一个FlowDocument来启用流内容托管。

流文档阅读器

FlowDocumentReader 包括使用户可以动态选择各种查看模式的功能,包括单页(一次页面)查看模式、一次两页(书籍阅读格式)查看模式和连续滚动(无底)查看模式。 有关这些查看模式的详细信息,请参阅 FlowDocumentReaderViewingMode。 如果不需要在不同查看模式之间动态切换的功能,FlowDocumentPageViewerFlowDocumentScrollViewer 提供在特定查看模式下固定的较轻量流内容查看器。

FlowDocumentPageViewer 和 FlowDocumentScrollViewer

FlowDocumentPageViewer 在单页查看模式下显示内容,而 FlowDocumentScrollViewer 以连续滚动模式显示内容。 FlowDocumentPageViewerFlowDocumentScrollViewer 都被固定在一个特定的查看模式上。 与 FlowDocumentReader相比,它包括使用户能够在各种查看模式(由 FlowDocumentReaderViewingMode 枚举提供)之间动态选择的功能,但资源消耗比 FlowDocumentPageViewerFlowDocumentScrollViewer更大。

默认情况下,始终显示垂直滚动条,如果需要,水平滚动条将变为可见。 FlowDocumentScrollViewer 的默认 UI 不包含工具栏;但是,可以使用 IsToolBarVisible 属性来启用内置工具栏。

RichTextBox

你希望允许用户编辑流内容时使用 RichTextBox 。 例如,如果你想要创建一个编辑器,该编辑器允许用户操作表格、斜体和粗体格式化等内容,你可以使用 RichTextBox。 有关详细信息,请参阅 RichTextBox 概述

注释

RichTextBox 内的流内容的行为不完全类似于其他控件中包含的流内容。 例如,RichTextBox 中没有列,因此没有自动调整大小行为。 此外,通常内置的流内容功能(如搜索、查看模式、页面导航和缩放)在一个 RichTextBox内部不可用。

创建流内容

流内容可能比较复杂,包括文本、图像、表甚至 UIElement 派生类(如控件)等各种元素。 若要了解如何创建复杂的流内容,以下几点至关重要:

  • 与流相关的类:流内容中使用的每个类都有特定的用途。 此外,流类之间的分层关系可帮助你了解它们的使用方式。 例如,从 Block 类派生的类用于包含其他对象,而从 Inline 类派生的类用于包含显示的对象。

  • 内容架构:流文档可能需要大量嵌套元素。 内容架构指定元素之间的可能的父/子关系。

以下部分将更详细地介绍其中每个方面。

下图显示了最常用于流内容的对象:

关系图:流内容元素类层次结构

出于流内容的目的,有两个重要类别:

  1. 块派生类:也称为“块内容元素”或仅“块元素”。 继承自 Block 的元素可用于对公共父级下的元素进行分组,或将公共属性应用于组。

  2. 内联派生类:也称为“内联内容元素”或“内联元素”。 继承自 Inline 的元素包含在 Block 元素或其他内联元素中。 内联元素通常用作呈现到屏幕的内容的直接容器。 例如, Paragraph (Block 元素)可以包含一个 Run (内联元素),但 Run 实际包含在屏幕上呈现的文本。

下面简要介绍了这两个类别中的每个类。

块导出类

段落

Paragraph 通常用于将内容分组到段落中。 段落的最简单和最常见的用法是创建文本段落。

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Paragraph>
    Some paragraph text.
  </Paragraph>
</FlowDocument>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
    public partial class ParagraphExample : Page
    {
        public ParagraphExample()
        {

            // Create paragraph with some text.
            Paragraph myParagraph = new Paragraph();
            myParagraph.Inlines.Add(new Run("Some paragraph text."));

            // Create a FlowDocument and add the paragraph to it.
            FlowDocument myFlowDocument = new FlowDocument();
            myFlowDocument.Blocks.Add(myParagraph);

            this.Content = myFlowDocument;
        }
    }
}

Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents

Namespace SDKSample
    Partial Public Class ParagraphExample
        Inherits Page
        Public Sub New()

            ' Create paragraph with some text.
            Dim myParagraph As New Paragraph()
            myParagraph.Inlines.Add(New Run("Some paragraph text."))

            ' Create a FlowDocument and add the paragraph to it.
            Dim myFlowDocument As New FlowDocument()
            myFlowDocument.Blocks.Add(myParagraph)

            Me.Content = myFlowDocument
        End Sub
    End Class
End Namespace

但是,还可以包含其他内联派生元素,如下所示。

章节

Section 仅用于包含其他 Block派生元素。 它不对包含的元素应用任何默认格式。 但是,在Section上设置的任何属性值都会应用到其子元素上。 通过节,还可以以编程方式循环访问其子集合。 Section的用法与 HTML 中的<DIV>标签相似。

在下面的示例中,三个段落被定义在一个 Section 下。 该部分的属性值为 Background Red,因此段落的背景色也为红色。

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <!-- By default, Section applies no formatting to elements contained
       within it. However, in this example, the section has a Background
       property value of "Red", therefore, the three paragraphs (the block)  
       inside the section also have a red background. -->
  <Section Background="Red">
    <Paragraph>
      Paragraph 1
    </Paragraph>
    <Paragraph>
      Paragraph 2
    </Paragraph>
    <Paragraph>
      Paragraph 3
    </Paragraph>
  </Section>
</FlowDocument>
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
    public partial class SectionExample : Page
    {
        public SectionExample()
        {

            // Create three paragraphs
            Paragraph myParagraph1 = new Paragraph(new Run("Paragraph 1"));
            Paragraph myParagraph2 = new Paragraph(new Run("Paragraph 2"));
            Paragraph myParagraph3 = new Paragraph(new Run("Paragraph 3"));

            // Create a Section and add the three paragraphs to it.
            Section mySection = new Section();
            mySection.Background = Brushes.Red;

            mySection.Blocks.Add(myParagraph1);
            mySection.Blocks.Add(myParagraph2);
            mySection.Blocks.Add(myParagraph3);

            // Create a FlowDocument and add the section to it.
            FlowDocument myFlowDocument = new FlowDocument();
            myFlowDocument.Blocks.Add(mySection);

            this.Content = myFlowDocument;
        }
    }
}

Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Controls
Imports System.Windows.Documents

Namespace SDKSample
    Partial Public Class SectionExample
        Inherits Page
        Public Sub New()

            ' Create three paragraphs
            Dim myParagraph1 As New Paragraph(New Run("Paragraph 1"))
            Dim myParagraph2 As New Paragraph(New Run("Paragraph 2"))
            Dim myParagraph3 As New Paragraph(New Run("Paragraph 3"))

            ' Create a Section and add the three paragraphs to it.
            Dim mySection As New Section()
            mySection.Background = Brushes.Red

            mySection.Blocks.Add(myParagraph1)
            mySection.Blocks.Add(myParagraph2)
            mySection.Blocks.Add(myParagraph3)

            ' Create a FlowDocument and add the section to it.
            Dim myFlowDocument As New FlowDocument()
            myFlowDocument.Blocks.Add(mySection)

            Me.Content = myFlowDocument
        End Sub
    End Class
End Namespace

BlockUIContainer

BlockUIContainer 使 UIElement 元素(即 a Button)嵌入在块派生的流内容中。 InlineUIContainer (请参阅下文)用于在内联派生流内容中嵌入 UIElement 元素。 BlockUIContainerInlineUIContainer 很重要,因为在流内容中使用 UIElement 的唯一方法是将其包含在这两个元素之一中。

以下示例演示如何使用 BlockUIContainer 元素在流内容中托管 UIElement 对象。

<FlowDocument ColumnWidth="400">
  <Section Background="GhostWhite">
    <Paragraph>
      A UIElement element may be embedded directly in flow content
      by enclosing it in a BlockUIContainer element.
    </Paragraph>
    <BlockUIContainer>
      <Button>Click me!</Button>
    </BlockUIContainer>
    <Paragraph>
      The BlockUIContainer element may host no more than one top-level
      UIElement.  However, other UIElements may be nested within the
      UIElement contained by an BlockUIContainer element.  For example,
      a StackPanel can be used to host multiple UIElement elements within
      a BlockUIContainer element.
    </Paragraph>
    <BlockUIContainer>
      <StackPanel>
        <Label Foreground="Blue">Choose a value:</Label>
        <ComboBox>
          <ComboBoxItem IsSelected="True">a</ComboBoxItem>
          <ComboBoxItem>b</ComboBoxItem>
          <ComboBoxItem>c</ComboBoxItem>
        </ComboBox>
        <Label Foreground ="Red">Choose a value:</Label>
        <StackPanel>
          <RadioButton>x</RadioButton>
          <RadioButton>y</RadioButton>
          <RadioButton>z</RadioButton>
        </StackPanel>
        <Label>Enter a value:</Label>
        <TextBox>
          A text editor embedded in flow content.
        </TextBox>
      </StackPanel>
    </BlockUIContainer>
  </Section>
</FlowDocument>

下图显示了此示例的呈现方式:

显示嵌入在流内容中的 UIElement 的屏幕截图。

列表

List 用于创建项目符号列表或数值列表。 将 MarkerStyle 属性设置为 TextMarkerStyle 枚举值,以确定列表的样式。 下面的示例演示如何创建简单列表。

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <List>
    <ListItem>
      <Paragraph>
        List Item 1
      </Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>
        List Item 2
      </Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>
        List Item 3
      </Paragraph>
    </ListItem>
  </List>
</FlowDocument>
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
    public partial class ListExample : Page
    {
        public ListExample()
        {

            // Create three paragraphs
            Paragraph myParagraph1 = new Paragraph(new Run("List Item 1"));
            Paragraph myParagraph2 = new Paragraph(new Run("List Item 2"));
            Paragraph myParagraph3 = new Paragraph(new Run("List Item 3"));

            // Create the ListItem elements for the List and add the
            // paragraphs to them.
            ListItem myListItem1 = new ListItem();
            myListItem1.Blocks.Add(myParagraph1);
            ListItem myListItem2 = new ListItem();
            myListItem2.Blocks.Add(myParagraph2);
            ListItem myListItem3 = new ListItem();
            myListItem3.Blocks.Add(myParagraph3);

            // Create a List and add the three ListItems to it.
            List myList = new List();

            myList.ListItems.Add(myListItem1);
            myList.ListItems.Add(myListItem2);
            myList.ListItems.Add(myListItem3);

            // Create a FlowDocument and add the section to it.
            FlowDocument myFlowDocument = new FlowDocument();
            myFlowDocument.Blocks.Add(myList);

            this.Content = myFlowDocument;
        }
    }
}

Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Controls
Imports System.Windows.Documents

Namespace SDKSample
    Partial Public Class ListExample
        Inherits Page
        Public Sub New()

            ' Create three paragraphs
            Dim myParagraph1 As New Paragraph(New Run("List Item 1"))
            Dim myParagraph2 As New Paragraph(New Run("List Item 2"))
            Dim myParagraph3 As New Paragraph(New Run("List Item 3"))

            ' Create the ListItem elements for the List and add the 
            ' paragraphs to them.
            Dim myListItem1 As New ListItem()
            myListItem1.Blocks.Add(myParagraph1)
            Dim myListItem2 As New ListItem()
            myListItem2.Blocks.Add(myParagraph2)
            Dim myListItem3 As New ListItem()
            myListItem3.Blocks.Add(myParagraph3)

            ' Create a List and add the three ListItems to it.
            Dim myList As New List()

            myList.ListItems.Add(myListItem1)
            myList.ListItems.Add(myListItem2)
            myList.ListItems.Add(myListItem3)

            ' Create a FlowDocument and add the section to it.
            Dim myFlowDocument As New FlowDocument()
            myFlowDocument.Blocks.Add(myList)

            Me.Content = myFlowDocument
        End Sub
    End Class
End Namespace

注释

List 是用于 ListItemCollection 管理子元素的唯一流元素。

Table 用于创建表。 Table 与元素类似 Grid ,但它具有更多功能,因此,需要更大的资源开销。 因为Grid是一个UIElement,所以它不能用于流内容,除非它被包含在BlockUIContainerInlineUIContainer中。 有关详细信息 Table,请参阅 表概述

内联派生类

运行

Run 用于包含未格式化的文本。 你可能希望 Run 对象在流内容中广泛使用。 但是,在标记中,Run 元素不需要显式使用。 Run 在使用代码创建或操作流程文档时是必需的。 例如,在下面的标记中,第一个 Paragraph 显式指定 Run 元素,而第二个元素则不指定。 这两个段落生成相同的输出。

<Paragraph>
  <Run>Paragraph that explicitly uses the Run element.</Run>
</Paragraph>

<Paragraph>
  This Paragraph omits the Run element in markup. It renders
  the same as a Paragraph with Run used explicitly. 
</Paragraph>

注释

从 .NET Framework 4 开始, Text 对象的属性 Run 是依赖属性。 可以将属性 Text 绑定到数据源,例如 TextBlock. 该 Text 属性完全支持单向绑定。 该 Text 属性还支持双向绑定,但除外 RichTextBox。 有关示例,请参阅 Run.Text

跨度

Span 将其他内联内容元素组合在一起。 不会对Span元素内的内容应用固有呈现。 但是,继承自 Span 的元素,包括 HyperlinkBoldItalicUnderline,确实将格式应用于文本。

下面是一个用于包含内联内容的示例Span,包括文本、Bold元素和Button

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Paragraph>
    Text before the Span. <Span Background="Red">Text within the Span is
    red and <Bold>this text is inside the Span-derived element Bold.</Bold>
    A Span can contain more then text, it can contain any inline content. For
    example, it can contain a 
    <InlineUIContainer>
      <Button>Button</Button>
    </InlineUIContainer>
    or other UIElement, a Floater, a Figure, etc.</Span>
  </Paragraph>

</FlowDocument>

以下屏幕截图显示了此示例的呈现方式。

屏幕截图:呈现的 Span 示例

InlineUIContainer

InlineUIContainer 使 UIElement 元素(例如 Button 控件)嵌入到 Inline 内容元素中。 此元素是前面提到的 BlockUIContainer 的内联等效元素。 下面是一个示例,使用InlineUIContainerParagraph中插入Button内联。

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Paragraph>
    Text to precede the button...

    <!-- Set the BaselineAlignment property to "Bottom" 
         so that the Button aligns properly with the text. -->
    <InlineUIContainer BaselineAlignment="Bottom">
      <Button>Button</Button>
    </InlineUIContainer>
    Text to follow the button...
  </Paragraph>

</FlowDocument>
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
    public partial class InlineUIContainerExample : Page
    {
        public InlineUIContainerExample()
        {
            Run run1 = new Run(" Text to precede the button... ");
            Run run2 = new Run(" Text to follow the button... ");

            // Create a new button to be hosted in the paragraph.
            Button myButton = new Button();
            myButton.Content = "Click me!";

            // Create a new InlineUIContainer to contain the Button.
            InlineUIContainer myInlineUIContainer = new InlineUIContainer();

            // Set the BaselineAlignment property to "Bottom" so that the
            // Button aligns properly with the text.
            myInlineUIContainer.BaselineAlignment = BaselineAlignment.Bottom;

            // Asign the button as the UI container's child.
            myInlineUIContainer.Child = myButton;

            // Create the paragraph and add content to it.
            Paragraph myParagraph = new Paragraph();
            myParagraph.Inlines.Add(run1);
            myParagraph.Inlines.Add(myInlineUIContainer);
            myParagraph.Inlines.Add(run2);

            // Create a FlowDocument and add the paragraph to it.
            FlowDocument myFlowDocument = new FlowDocument();
            myFlowDocument.Blocks.Add(myParagraph);

            this.Content = myFlowDocument;
        }
    }
}

Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Controls
Imports System.Windows.Documents

Namespace SDKSample
    Partial Public Class InlineUIContainerExample
        Inherits Page
        Public Sub New()
            Dim run1 As New Run(" Text to precede the button... ")
            Dim run2 As New Run(" Text to follow the button... ")

            ' Create a new button to be hosted in the paragraph.
            Dim myButton As New Button()
            myButton.Content = "Click me!"

            ' Create a new InlineUIContainer to contain the Button.
            Dim myInlineUIContainer As New InlineUIContainer()

            ' Set the BaselineAlignment property to "Bottom" so that the 
            ' Button aligns properly with the text.
            myInlineUIContainer.BaselineAlignment = BaselineAlignment.Bottom

            ' Asign the button as the UI container's child.
            myInlineUIContainer.Child = myButton

            ' Create the paragraph and add content to it.
            Dim myParagraph As New Paragraph()
            myParagraph.Inlines.Add(run1)
            myParagraph.Inlines.Add(myInlineUIContainer)
            myParagraph.Inlines.Add(run2)

            ' Create a FlowDocument and add the paragraph to it.
            Dim myFlowDocument As New FlowDocument()
            myFlowDocument.Blocks.Add(myParagraph)

            Me.Content = myFlowDocument
        End Sub
    End Class
End Namespace

注释

InlineUIContainer 不需要在标记中显式使用。 如果省略它,代码编译时仍然会创建一个 InlineUIContainer

图和漂浮物

FigureFloater 用于在流文档中嵌入内容,其中放置属性可以独立于主要内容流进行自定义。 FigureFloater 元素通常用于突出显示或强调部分内容、托管支持图像或主内容流中的其他内容,或注入松散相关的内容,如广告。

下面的示例演示如何将 a Figure 嵌入文本段落。

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Paragraph>
    <Figure 
      Width="300" Height="100" 
      Background="GhostWhite" HorizontalAnchor="PageLeft" >
      <Paragraph FontStyle="Italic" Background="Beige" Foreground="DarkGreen" >
        A Figure embeds content into flow content with placement properties 
        that can be customized independently from the primary content flow
      </Paragraph>
    </Figure>
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy
    nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi
    enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis
    nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure.
  </Paragraph>

</FlowDocument>
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
    public partial class FigureExample : Page
    {
        public FigureExample()
        {

            // Create strings to use as content.
            string strFigure = "A Figure embeds content into flow content with" +
                               " placement properties that can be customized" +
                               " independently from the primary content flow";
            string strOther = "Lorem ipsum dolor sit amet, consectetuer adipiscing" +
                              " elit, sed diam nonummy nibh euismod tincidunt ut laoreet" +
                              " dolore magna aliquam erat volutpat. Ut wisi enim ad" +
                              " minim veniam, quis nostrud exerci tation ullamcorper" +
                              " suscipit lobortis nisl ut aliquip ex ea commodo consequat." +
                              " Duis autem vel eum iriure.";

            // Create a Figure and assign content and layout properties to it.
            Figure myFigure = new Figure();
            myFigure.Width = new FigureLength(300);
            myFigure.Height = new FigureLength(100);
            myFigure.Background = Brushes.GhostWhite;
            myFigure.HorizontalAnchor = FigureHorizontalAnchor.PageLeft;
            Paragraph myFigureParagraph = new Paragraph(new Run(strFigure));
            myFigureParagraph.FontStyle = FontStyles.Italic;
            myFigureParagraph.Background = Brushes.Beige;
            myFigureParagraph.Foreground = Brushes.DarkGreen;
            myFigure.Blocks.Add(myFigureParagraph);

            // Create the paragraph and add content to it.
            Paragraph myParagraph = new Paragraph();
            myParagraph.Inlines.Add(myFigure);
            myParagraph.Inlines.Add(new Run(strOther));

            // Create a FlowDocument and add the paragraph to it.
            FlowDocument myFlowDocument = new FlowDocument();
            myFlowDocument.Blocks.Add(myParagraph);

            this.Content = myFlowDocument;
        }
    }
}

Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Controls
Imports System.Windows.Documents

Namespace SDKSample
    Partial Public Class FigureExample
        Inherits Page
        Public Sub New()

            ' Create strings to use as content.
            Dim strFigure As String = "A Figure embeds content into flow content with" & " placement properties that can be customized" & " independently from the primary content flow"
            Dim strOther As String = "Lorem ipsum dolor sit amet, consectetuer adipiscing" & " elit, sed diam nonummy nibh euismod tincidunt ut laoreet" & " dolore magna aliquam erat volutpat. Ut wisi enim ad" & " minim veniam, quis nostrud exerci tation ullamcorper" & " suscipit lobortis nisl ut aliquip ex ea commodo consequat." & " Duis autem vel eum iriure."

            ' Create a Figure and assign content and layout properties to it.
            Dim myFigure As New Figure()
            myFigure.Width = New FigureLength(300)
            myFigure.Height = New FigureLength(100)
            myFigure.Background = Brushes.GhostWhite
            myFigure.HorizontalAnchor = FigureHorizontalAnchor.PageLeft
            Dim myFigureParagraph As New Paragraph(New Run(strFigure))
            myFigureParagraph.FontStyle = FontStyles.Italic
            myFigureParagraph.Background = Brushes.Beige
            myFigureParagraph.Foreground = Brushes.DarkGreen
            myFigure.Blocks.Add(myFigureParagraph)

            ' Create the paragraph and add content to it.
            Dim myParagraph As New Paragraph()
            myParagraph.Inlines.Add(myFigure)
            myParagraph.Inlines.Add(New Run(strOther))

            ' Create a FlowDocument and add the paragraph to it.
            Dim myFlowDocument As New FlowDocument()
            myFlowDocument.Blocks.Add(myParagraph)

            Me.Content = myFlowDocument
        End Sub
    End Class
End Namespace

下图显示了此示例的呈现方式。

屏幕截图:图示例

FigureFloater 在多方面有所不同,并用于不同的情境。

图:

  • 可定位:您可以设置其水平和垂直定位点,使其相对于页面、内容、列或段落来停靠。 还可以使用其 HorizontalOffset 属性 VerticalOffset 来指定任意偏移量。

  • 可以调整为跨多个列:您可以将 Figure 的高度和宽度设置为页面、内容或列高度或宽度的倍数。 请注意,对于页面和内容,不允许大于 1 的倍数。 例如,可以将宽度 Figure 设置为“0.5 页”或“0.25 内容”或“2 列”。 还可以将高度和宽度设置为绝对像素值。

  • 不分页处理:如果 Figure 内的内容不适合在 Figure 内,它将渲染适合的内容,而剩余内容将丢失。

浮子:

  • 无法定位,将在任何可用空间中显示。 不能设置偏移量或将 Floater 定位。

  • 不能调整为多个列的大小:默认情况下, Floater 大小为一列。 它有一个 Width 属性,可以设置为绝对像素值,但如果此值大于一列宽度,则忽略它,并且浮点数大小为一列。 可以通过设置正确的像素宽度将其大小调整为小于一列,但大小不是列相对的,因此“0.5Column”不是宽度的有效表达式 FloaterFloater 没有 height 属性,并且无法设置高度,高度取决于内容

  • Floater分页:如果其内容在指定宽度下扩展到超过 1 列的高度,浮动元素将中断并分页到下一列、下一页等。

Figure 是放置独立内容的好位置,可在其中控制大小和定位,并且确信内容适合指定大小。 Floater 是放置更多自由流动的内容的位置,这些内容与主页内容类似,但与主页内容分开。

LineBreak

LineBreak 导致流内容中出现换行符。 下面的示例演示了如何使用 LineBreak

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Paragraph>
    Before the LineBreak in Paragraph.
    <LineBreak />
    After the LineBreak in Paragraph.
    <LineBreak/><LineBreak/>
    After two LineBreaks in Paragraph.
  </Paragraph>

  <Paragraph>
    <LineBreak/>
  </Paragraph>

  <Paragraph>
    After a Paragraph with only a LineBreak in it.
  </Paragraph>
</FlowDocument>

以下屏幕截图显示了此示例的呈现方式。

屏幕截图:LineBreak 示例

流集合元素

在上述许多示例中,使用 BlockCollectionInlineCollection 编程构造流内容。 例如,若要向 a Paragraph添加元素,可以使用语法:

myParagraph.Inlines.Add(new Run("Some text"));

这会向 ParagraphInlineCollection 添加一个 Run。 这与在标记中的Paragraph内部发现的隐式Run相同:

<Paragraph>
Some Text
</Paragraph>

下面这个示例演示如何使用BlockCollection;首先创建一个新的Section,然后使用Add方法将一个新的Paragraph添加到Section内容中。

Section secx = new Section();
secx.Blocks.Add(new Paragraph(new Run("A bit of text content...")));
Dim secx As New Section()
secx.Blocks.Add(New Paragraph(New Run("A bit of text content...")))

除了将项添加到流集合之外,还可以删除项。 以下示例删除 Inline中的最后一个 Span 元素。

spanx.Inlines.Remove(spanx.Inlines.LastInline);
spanx.Inlines.Remove(spanx.Inlines.LastInline)

以下示例将 Inline中的所有内容(Span 元素)清除。

spanx.Inlines.Clear();
spanx.Inlines.Clear()

以编程方式处理流内容时,可能会广泛使用这些集合。

流元素使用InlineCollection(行内元素)或BlockCollection(块级元素)来包含其子元素,这取决于父元素可以包含哪种类型的子元素(BlockInline)。 下一部分的内容架构中汇总了流内容元素的包含规则。

注释

有第三种类型的集合与流内容一起使用, ListItemCollection但此集合仅用于一个 List。 此外,有多个集合与 Table 一起使用。 有关详细信息,请参阅 表概述

内容架构

给定不同流内容元素的数量,跟踪元素可以包含的子元素类型可能非常困难。 下图汇总了流元素的包含规则。 箭头表示可能的父/子关系。

示意图:流内容包含架构

如上图所示,允许元素的子级不一定取决于它是 Block 元素还是 Inline 元素。 例如,Span(元素Inline)只能有Inline子元素,而Figure(也是元素Inline)只能有Block子元素。 因此,关系图可用于快速确定可包含在另一个元素中的元素。 例如,让我们使用示意图来确定如何构建 RichTextBox的流程内容。

1.RichTextBox 必须包含一个 FlowDocument,并且该 FlowDocument 必须包含一个从 Block 派生的对象。 下面是上图中的相应段。

示意图:RichTextBox 包含规则

到此为止,标记可能类似于所示内容。

<RichTextBox>
  <FlowDocument>
    <!-- One or more Block-derived object… -->
  </FlowDocument>
</RichTextBox>

2. 根据关系图,有几个Block元素可供选择,包括ParagraphSectionTableListBlockUIContainer(请参阅上面的块派生类)。 假设需要一个 Table。 根据上图,Table 包含一个 TableRowGroup,其中包含 TableRow 元素,这些元素中又包含 TableCell 元素,而这些元素包含一个 Block 派生对象。 下面是从上图中提取的对应段 Table

示意图:表的父/子架构 的父/子架构

下面是相应的标记。

<RichTextBox>
  <FlowDocument>
    <Table>
      <TableRowGroup>
        <TableRow>
          <TableCell>
            <!-- One or more Block-derived object… -->
          </TableCell>
        </TableRow>
      </TableRowGroup>
    </Table>
  </FlowDocument>
</RichTextBox>

3. 同样,在某个TableCell元素下需要一个或多个Block元素。 为简单起见,在单元格内部放置一些文本。 可以使用 ParagraphRun 元素来执行此操作。 下面是图表中对应的段落,显示 Paragraph 可以包含 Inline 元素,而 RunInline 元素)只能包含纯文本。

示意图:段落的父/子架构 的父/子架构

示意图:运行的父/子架构 的父/子架构

下面是标记语言中的整个示例。

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <RichTextBox>
    <FlowDocument>
      
      <!-- Normally a table would have multiple rows and multiple
           cells but this code is for demonstration purposes.-->
      <Table>
        <TableRowGroup>
          <TableRow>
            <TableCell>
              <Paragraph>

                <!-- The schema does not actually require
                     explicit use of the Run tag in markup. It 
                     is only included here for clarity. -->
                <Run>Paragraph in a Table Cell.</Run>
              </Paragraph>
            </TableCell>
          </TableRow>
        </TableRowGroup>
      </Table>

    </FlowDocument>
  </RichTextBox>
</Page>

自定义文本

通常,文本是流文档中最常见的内容类型。 尽管上述对象可用于控制文本呈现方式的大多数方面,但有一些其他方法可用于自定义本节中介绍的文本。

文本修饰

通过文本修饰,可以将下划线、超行、基线和删除线效果应用于文本(请参阅下面的图片)。 这些修饰是使用TextDecorations属性添加的,该属性由许多对象公开,包括InlineParagraphTextBlockTextBox

以下示例展示如何设置ParagraphTextDecorations属性。

<FlowDocument ColumnWidth="200">
  <Paragraph TextDecorations="Strikethrough">
    This text will render with the strikethrough effect.
  </Paragraph>
</FlowDocument>
Paragraph parx = new Paragraph(new Run("This text will render with the strikethrough effect."));
parx.TextDecorations = TextDecorations.Strikethrough;
Dim parx As New Paragraph(New Run("This text will render with the strikethrough effect."))
parx.TextDecorations = TextDecorations.Strikethrough

下图显示了此示例的呈现方式。

屏幕截图:具有默认删除线效果的文本

下图显示了 “超线”、“ 基线”和 “下划线 ”修饰的呈现方式。

屏幕截图:超行 TextDecorator

屏幕截图:文本Inline_TextDec_Base的默认基线效果

屏幕截图:具有默认下划线效果

字体设计

Typography属性由大多数与流相关的内容(包括TextElementFlowDocumentTextBlockTextBox)公开。 此属性用于控制文本的版式特征和变体(即小写字母或大写字母、上标和下标等)。

以下示例演示如何设置 Typography 属性,使用 Paragraph 作为示例元素。

<Paragraph
  TextAlignment="Left"
  FontSize="18" 
  FontFamily="Palatino Linotype"
  Typography.NumeralStyle="OldStyle"
  Typography.Fraction="Stacked"
  Typography.Variants="Inferior"
>
  <Run>
    This text has some altered typography characteristics.  Note
    that use of an open type font is necessary for most typographic
    properties to be effective.
  </Run>
  <LineBreak/><LineBreak/>
  <Run>
    0123456789 10 11 12 13
  </Run>
  <LineBreak/><LineBreak/>
  <Run>
    1/2 2/3 3/4
  </Run>
</Paragraph>

下图显示了此示例的呈现方式。

显示带有更改版式的文本的屏幕截图。

相比之下,下图显示了使用默认版式属性呈现的类似示例。

显示具有默认版式的文本的屏幕截图。

以下示例演示如何以编程方式设置 Typography 属性。

Paragraph par = new Paragraph();

Run runText = new Run(
    "This text has some altered typography characteristics.  Note" +
    "that use of an open type font is necessary for most typographic" +
    "properties to be effective.");
Run runNumerals = new Run("0123456789 10 11 12 13");
Run runFractions = new Run("1/2 2/3 3/4");

par.Inlines.Add(runText);
par.Inlines.Add(new LineBreak());
par.Inlines.Add(new LineBreak());
par.Inlines.Add(runNumerals);
par.Inlines.Add(new LineBreak());
par.Inlines.Add(new LineBreak());
par.Inlines.Add(runFractions);

par.TextAlignment = TextAlignment.Left;
par.FontSize = 18;
par.FontFamily = new FontFamily("Palatino Linotype");

par.Typography.NumeralStyle = FontNumeralStyle.OldStyle;
par.Typography.Fraction = FontFraction.Stacked;
par.Typography.Variants = FontVariants.Inferior;
Dim par As New Paragraph()

Dim runText As New Run("This text has some altered typography characteristics.  Note" & "that use of an open type font is necessary for most typographic" & "properties to be effective.")
Dim runNumerals As New Run("0123456789 10 11 12 13")
Dim runFractions As New Run("1/2 2/3 3/4")

par.Inlines.Add(runText)
par.Inlines.Add(New LineBreak())
par.Inlines.Add(New LineBreak())
par.Inlines.Add(runNumerals)
par.Inlines.Add(New LineBreak())
par.Inlines.Add(New LineBreak())
par.Inlines.Add(runFractions)

par.TextAlignment = TextAlignment.Left
par.FontSize = 18
par.FontFamily = New FontFamily("Palatino Linotype")

par.Typography.NumeralStyle = FontNumeralStyle.OldStyle
par.Typography.Fraction = FontFraction.Stacked
par.Typography.Variants = FontVariants.Inferior

有关排版的更多信息,请参阅 WPF 中的排版

另请参阅