Общие сведения о документе нефиксированного формата

Документы нефиксированного формата разработаны для оптимизации просмотра и удобства чтения. Документы нефиксированного формата не зависят от предварительно определенного макета, а динамически изменяют и переформатируют свое содержимое на основе переменных времени выполнения (например, размера окна и разрешения устройства) и дополнительных пользовательских настроек. Кроме того, документы нефиксированного формата предоставляют дополнительные возможности, например, разбиение на страницы и столбцы. В этом разделе представлен обзор документов нефиксированного формата и способов их создания.

В этом разделе содержатся следующие подразделы.

  • Что такое документ нефиксированного формата
  • Типы документов нефиксированного формата
  • Создание содержимого нефиксированного формата
  • Классы, связанные с нефиксированным форматом
  • Схема содержимого
  • Настройка текста
  • Связанные разделы

Что такое документ нефиксированного формата

Документ нефиксированного формата предназначен для «переформатирования содержимого» в зависимости от размера окна, разрешения устройства и других переменных среды. Кроме того, документы нефиксированного формата имеют множество встроенных возможностей, включая поиск, просмотр режимов оптимизации удобочитаемости и возможность изменения размера и вида шрифтов. Документы нефиксированного формата лучше всего подходят для тех случаев, когда удобочитаемость является определяющей при использовании документа. Форматы фиксированного документа, напротив, разработаны для статического представления. Форматы фиксированного документа полезны в тех случаях, когда важна точность содержимого источника. Дополнительные сведения о различных типах документов см. в разделе Документы в WPF.

Ниже показан образец документа нефиксированного формата, отображенного в нескольких окнах различных размеров. При изменении области отображения содержимое переформатируется, чтобы обеспечить наилучшее использование доступного места.

Повторный поток содержимого документа нефиксированного формата

Как показано на рисунке выше, содержимое нефиксированного формата может включать многие компоненты, в том числе абзацы, списки, изображения и др. Эти компоненты соответствуют элементам в разметке и объектам в процедуре кода. Подробнее эти классы будут рассмотрены далее в разделе Классы, связанные с нефиксированным форматом этого обзора. Здесь представлен простой пример кода, который создает документ нефиксированного формата, состоящий из абзаца с жирным текстом и списка.

<!-- This simple flow document includes a paragraph with some
     bold text in it and a list. -->
<FlowDocumentReader xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://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>

Imports System
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
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;
        }
    }
}

На рисунке ниже показан этот фрагмент кода.

Снимок экрана: пример отображенного документа нефиксированного формата

В этом примере элемент управления FlowDocumentReader используется для размещения содержимого нефиксированного формата. См. раздел Типы документов нефиксированного формата для получения дополнительных сведений об элементах управления, размещающих поточное содержимое. Элементы Paragraph, List, ListItem и Bold используются для управления форматированием содержимого в зависимости от их порядка в разметке. Например, элемент Bold охватывает только часть текста в абзаце; в результате только эта часть текста будет выделена жирным шрифтом. Пользователям HTML это поведение будет знакомо.

Как показано на рисунке выше, документы нефиксированного формата имеют несколько встроенных возможностей:

  • Поиск: позволяет пользователю выполнять полнотекстовый поиск по всему документу.

  • Режим просмотра: пользователь может выбрать для себя предпочтительный режим просмотра, например постраничный режим просмотра (просмотр страницы целиком), двустраничный режим просмотра (книжный формат) и режим просмотра с непрерывной прокруткой («без дна»). Дополнительные сведения об этих режимах просмотра содержатся в разделе FlowDocumentReaderViewingMode.

  • Элементы управления постраничной навигации: если режим просмотра документа использует страницы, то элементы управления навигацией по страницам содержат кнопку для перехода к следующей странице (стрелка вниз) или к предыдущей странице (стрелка вверх), а также индикаторы текущего номера страницы и общего количества страниц. Пролистывание страниц также может быть выполнено с помощью клавиш со стрелками на клавиатуре.

  • Увеличение: элементы управления масштабом позволяют пользователю увеличить или уменьшить масштаб, щелкнув кнопки со знаками «плюс» или «минус» соответственно. Элементы управления масштабом также включают ползунок для изменения масштаба. Дополнительные сведения см. в разделе Zoom.

Эти возможности могут быть в зависимости от элемента управления, используемого для размещения содержимого нефиксированного формата. В следующем разделе описаны различные элементы управления.

Типы документов нефиксированного формата

Отображение содержимого документа нефиксированного формата и его вид зависят от того, какой объект используется для размещения содержимого нефиксированного формата. Существуют четыре элемента управления, поддерживающие просмотр содержимого нефиксированного формата: FlowDocumentReader, FlowDocumentPageViewer, RichTextBox и FlowDocumentScrollViewer. Эти элементы управления кратко описаны ниже.

Обратите внимание: для непосредственного размещения содержимого нефиксированного формата необходим FlowDocument. Таким образом, все эти элементы управления просмотром используют FlowDocument для размещения содержимого нефиксированного формата.

Элемент управления FlowDocumentReader

FlowDocumentReader включает возможности, позволяющие пользователю динамически выбирать различные режимы просмотра, включая одностраничный (постраничный), двухстраничный (книжный формат) и режим просмотра непрерывной прокрутки («без дна»). Дополнительные сведения об этих режимах просмотра содержатся в разделе FlowDocumentReaderViewingMode. Если динамическое переключение между режимами просмотра не требуется, элементы управления FlowDocumentPageViewer и FlowDocumentScrollViewer предоставляют облегченные средства просмотра содержимого документа нефиксированного формата, закрепленные для определенного режима просмотра.

FlowDocumentPageViewer и FlowDocumentScrollViewer

Элемент управления FlowDocumentPageViewer отображает содержимое в режиме постраничного просмотра, а FlowDocumentScrollViewer отображает содержимое в режиме непрерывной прокрутки. Оба элемента управления FlowDocumentPageViewer и FlowDocumentScrollViewer предназначены только для конкретного режима просмотра. Это отличает их от элемента управления FlowDocumentReader, который включает в себя возможности, позволяющие пользователю динамически выбирать различные режимы просмотра (представленные перечислением FlowDocumentReaderViewingMode), что делает его более ресурсоемким, чем элементы управления FlowDocumentPageViewer или FlowDocumentScrollViewer.

По умолчанию вертикальная полоса прокрутки отображается всегда, а горизонтальная становится видимой при необходимости. Пользовательский интерфейс по умолчанию для объекта FlowDocumentScrollViewer не содержит панели инструментов, но для включения встроенной панели инструментов можно использовать свойство IsToolBarVisible.

RichTextBox

Если необходимо разрешить пользователю изменять содержимое нефиксированного формата, используйте RichTextBox. Например, чтобы создать редактор, который позволял бы пользователю манипулировать такими элементами, как таблицы, форматирование курсива и жирного шрифта и т.д,, следует использовать RichTextBox. Дополнительные сведения см. в разделе Общие сведения о RichTextBox.

Примечание Содержимое потока внутри RichTextBox ведет себя не так, как содержимое потока, имеющееся в других элементах управления. Например, в RichTextBox нет столбцов и, следовательно, нет автоматического изменения размеров. Кроме того, в RichTextBox недоступны обычные встроенные возможности поточного содержимого, например поиск, режим просмотра, навигация по страницам и увеличение.

Создание содержимого нефиксированного формата

Содержимое нефиксированного формата может быть сложным, т.е. состоящим из различных элементов, включая текст, изображения, таблицы и даже UIElement производных классов (например, элементов управления). Чтобы понять, как создать сложное поточное содержимое, важно понимать следующее:

  • Классы, связанные с нефиксированным форматом: каждый класс, используемый в содержимом нефиксированного формата, имеет особое назначение. Кроме того, иерархическая связь между классами нефиксированного формата помогает понять, как они используются. Например, классы, производные от класса Block, используются для размещения других объектов, а классы, производные от Inline, содержат отображаемые объекты.

  • Схема содержимого: документ нефиксированного формата может потребовать значительное число вложенных элементов. Схема содержимого указывает возможные связи «родитель/потомок» между элементами.

В следующих разделах каждый из этих пунктов будет рассмотрена более подробно.

Классы, связанные с нефиксированным форматом

Представленная ниже диаграмма показывает объекты, чаще всего использующиеся вместе с содержимым нефиксированного формата:

Схема: иерархия класса элемента потока содержимого

Для содержимого нефиксированного формата существуют две важные категории:

  1. Классы, производные от блока: также называющиеся «элементы блок-содержимого» или просто «блок-элементы». Элементы, которые наследуются от Block, можно использовать для группировки элементов по общему родителю или для применения к группе общих атрибутов.

  2. Классы, производные от встроенных элементов: также называющиеся «элементы встроенного содержимого» или просто «встроенные элементы». Элементы, которые наследуются от Inline, содержатся в блок-элементе или в другом встроенном элементе. Встроенные элементы часто используются в качестве непосредственного контейнера содержимого, отображаемого на экране. Например, Paragraph (блок-элемент) может содержать Run (встроенный элемент), но Run фактически содержит текст, отображаемый на экране.

Ниже кратко описан каждый класс этих категорий.

Классы, производные от блоков

Paragraph

Paragraph обычно используется для группировки содержимого в абзаце. Чаще всего Paragraph используется для создания абзаца текста.

<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
  <Paragraph>
    Some paragraph text.
  </Paragraph>
</FlowDocument>

Imports System
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
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;
        }
    }
}

Тем не менее, здесь можно включить и другие встроенные элементы, как будет показано ниже.

Раздел

Section используется только для размещения других элементов, производных от Block. Не применяет никакого форматирования по умолчанию к содержащимся в нем элементам. В то же время, любые значения свойства, установленные на Section, применяются к его дочерним элементам. Раздел также позволяет программно перебирать свою дочернюю коллекцию. Элемент Section используется таким же образом, как тег <DIV> в HTML.

В приведенном ниже примере три абзаца определяются под одним Section. Значение свойства Background раздела равно Red, поэтому цвет фона абзаца тоже красный.

<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://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>

Imports System
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
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;
        }
    }
}

BlockUIContainer

Элемент BlockUIContainer позволяет элементам UIElement (например, элементам Button) встраиваться в блочное потоковое содержимое. Элемент InlineUIContainer (см. ниже) используется для внедрения элементов UIElement во встроенное поточное содержимое. Элементы BlockUIContainer и InlineUIContainer важны, поскольку использовать элемент 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

List используется для создания маркированного или нумерованного списка. Задайте свойству MarkerStyle значение перечисления TextMarkerStyle для определения стиля в списке. Следующий пример показывает, как создать простой список.

<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://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>

Imports System
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
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;
        }
    }
}

Обратите внимание: List является единственным элементом нефиксированного формата, использующим ListItemCollection для управления дочерними элементами.

Таблица

Элемент Table используется для создания таблицы. Элемент Table аналогичен элементу Grid, однако имеет больше возможностей и, таким образом, требует больших ресурсов. Поскольку Grid является UIElement, то он не может использоваться в содержимом нефиксированного формата за исключением того случая, когда он содержится в BlockUIContainer или InlineUIContainer. Дополнительные сведения о Table см. в разделе Общие сведения о таблицах.

Классы, производные от встроенных

Запуск

Run используется для хранения неформатированного текста. Объекты Run обычно интенсивно используются в нефиксированном содержимом. Впрочем, в разметке не требуется явное использование элементов Run. При создании документов нефиксированного формата и управлении ими с помощью кода необходимо использовать класс Run. Например, в приведенной ниже разметке первый Paragraph в явном виде задает элемент Run, а второй — не задает его. Оба абзаца создают идентичные выходные данные.

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

<Paragraph>
  This Paragraph omits the 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 не применяется никакое обязательное отображение. В то же время, элементы, которые наследуются от Span (включая Hyperlink, Bold, Italic и Underline), применяют форматирование к тексту.

Ниже приведен пример использования Span для хранения встроенного содержимого, в том числе текста, элемента Bold и Button.

<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://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. Ниже приведен пример, который использует InlineUIContainer для вставки встроенных Button в Paragraph.

<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://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>

Imports System
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
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;
        }
    }
}

Обратите внимание: в разметке не требуется в явном виде использовать InlineUIContainer. Если им пренебречь, то при компиляции кода в любом случае будет создан InlineUIContainer.

Figure и Floater

Элементы Figure и Floater используются для внедрения содержимого в документ нефиксированного формата; при этом свойства размещения могут быть настроены независимо от основного потока содержимого. Элементы Figure или Floater часто используются для выделения или подчеркивания частей содержимого, для размещения сопровождающих изображений или другого содержимого в рамках основного потока или для добавления не связанного с основным документом содержимого, например рекламы.

Следующий пример показывает, как внедрить Figure в абзац текста.

<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://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>

Imports System
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
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;
        }
    }
}

Следующий рисунок показывает результат отображения этого примера.

Снимок экрана: пример фигуры

Figure и Floater немного отличаются и используются для различных скриптов.

Figure:

  • Для элемента можно определить местоположение. Для закрепления относительно страницы, содержимого, столбца или абзаца можно задать горизонтальные и вертикальные точки привязки. Также для указания произвольного смещения можно использовать его свойства HorizontalOffset и VerticalOffset.

  • Элемент можно разместить в нескольких столбцах. Можно установить высоту и ширину Figure в значения, кратные странице, содержимому, высоте или ширине столбца. Обратите внимание, что в случае страницы и содержимого, кратности больше 1 не допускаются. Например, можно установить значение ширины Figure равным «0.5 страницы», «0.25 содержимого» или «2 столбца». Значения высоты и ширины также можно установить в абсолютных значениях.

  • Элемент не разбивается постранично. Если содержимое в Figure не помещается внутри Figure, будет отображаться все поместившееся содержимое, а не помещающаяся часть будет утеряна

Floater:

  • Для элемента невозможно определить местоположение, и он будет отображаться в любом доступном для него месте. Задать смещение или значение привязки Floater невозможно.

  • Не может изменяться по размеру до размера большего, чем один столбец. По умолчанию Floater имеет размер, равный одному столбцу. Свойство элемента Width может быть задано в абсолютных точках, но в случае, если это значение превышает ширину одного столбца, оно будет игнорироваться, а размеры плавающего объекта изменятся до размера одного столбца. Можно сделать его уже, чем один столбец, задав правильную ширину в пикселях, но нельзя задать ширину относительно ширины столбца; "0.5 столбца" — неправильное значение ширины элемента Floater. Элемент Floater лишен свойства высоты; его высота не может быть указана, она зависит от содержимого.

  • Floater переносится постранично. Если его содержимое в заданной ширине расширяется на более чем 1 высоту столбца, плавающий объект прерывается и переходит в следующий столбец, страницу и т.д.

Элемент Figure хорошо подходит для размещения обособленного содержимого, если необходимо контролировать его размер и размещение, и можно быть уверенным в том, что он поместится в заданные размеры. Элемент Floater больше подходит для размещения более свободного содержимого, расположенного подобно содержимому основной страницы, но отделенного от него.

LineBreak

LineBreak вызывает разрыв строки в содержимом нефиксированного формата. В следующем примере показано использование LineBreak.

<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://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

Элементы коллекции нефиксированного формата

В большинстве приведенных выше примеров BlockCollection и InlineCollection используются для построения содержимого нефиксированного формата программными средствами. Например, чтобы добавить элементы в Paragraph, можно использовать следующий синтаксис:

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

Это добавляет Run в InlineCollection абзаца Paragraph. Этот пример совпадает со случаем, когда в разметке найден неявный Run внутри Paragraph:

<Paragraph>

Some Text

</Paragraph>

В качестве примера использования BlockCollection, в следующем примере создается новый Section. Затем метод Add используется для добавления нового Paragraph в содержимое Section.

            Dim secx As New Section()
            secx.Blocks.Add(New Paragraph(New Run("A bit of text content...")))
Section secx = 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 (блоков) для хранения своих дочерних элементов зависит от того, какой тип дочерних элементов могут содержать родители (Block или Inline). Правила включения для элементов содержимого нефиксированного формата приводятся в схеме содержимого в следующем разделе.

Обратите внимание: существует третий тип коллекции, используемый с содержимым нефиксированного формата — ListItemCollection. Эта коллекция используется только с List. Кроме того, существует несколько коллекций, используемых с Table. Дополнительные сведения см. в разделе Общие сведения о таблицах.

Схема содержимого

Учитывая число различных элементов содержимого нефиксированного формата, отслеживание того, какие типы дочерних элементов может содержать элемент, может быть достаточно сложной задачей. На схеме ниже представлены правила включения для элементов нефиксированного формата. Стрелки показывают возможные связи «родитель/потомок».

Схема: схема вместимости потока содержимого

Как видно из диаграммы выше, потомки для элемента не обязательно определяются элементами Block или Inline. Например, Span (элемент Inline) может иметь только дочерние элементы Inline, в то время как Figure (также элемент Inline) может иметь только дочерние элементы Block. Таким образом, диаграмма может служить для быстрого определения элемента, который может содержаться в другом элементе. Для примера используем диаграмму, чтобы определить, как создать содержимое нефиксированного формата RichTextBox.

1. Объект RichTextBox должен содержать FlowDocument, который в свою очередь должен содержать объект, производный от Block. Ниже приведен соответствующий сегмент из схемы.

Схема: правила вместимости RichTextBox

Разметка может выглядеть следующим образом:

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

2. В соответствии с диаграммой существует несколько элементов класса Block для выбора, в том числе: Paragraph, Section, Table, List и BlockUIContainer (см. выше классы, производные от блока). Предположим, нам требуется 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. Для удобства поместим часть текста в ячейку. Это можно сделать, используя Paragraph с элементом Run. Ниже приводится соответствующий сегмент из диаграммы, показывающий, что Paragraph может принять элемент Inline, а также что Run (элемент Inline) может принять только обычный текст.

Схема: схема родительский/дочерний элементы для параграфаСхема: схема родительский/дочерний элементы для запуска

Ниже в разметке приведен полный пример.

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://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, которое отображается числом объектов, включающих Inline, Paragraph TextBlock и TextBox.

В следующем примере показано, как задать свойство TextDecorations абзаца Paragraph.

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

На следующем рисунке показан результат выполнения этого примера.

Снимок экрана: текст с эффектом зачеркивания по умолчанию

Следующие иллюстрации показывают отображения эффектов оформления Overline, Baseline и Underline соответственно.

Снимок экрана: надстрочный TextDecoratorСнимок экрана: эффект базового плана для текста по умолчаниюСнимок экрана: текст с эффектом подчеркивания по умолчанию

Типографская разметка

Свойство Typography предоставляется большей частью содержимого, связанного с нефиксированным форматом, в том числе TextElement, FlowDocument TextBlock и TextBox. Это свойство используется для контроля типографских характеристик текста (т. е. прописных или строчных букв, надстрочных и подстрочных символов и т. д.).

В следующем примере показано, как установить атрибут 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.

            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
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;

Дополнительные сведения о типографской разметке текста см. в разделе Оформление в WPF.

См. также

Основные понятия

Оптимизация производительности: отображение текста

Оформление в WPF

Общие сведения о модели содержимого TextElement

Общие сведения о RichTextBox

Документы в WPF

Общие сведения о таблицах

Общие сведения о заметках

Другие ресурсы

Разделы пошагового руководства, посвященные элементам содержимого нефиксированного формата