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

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

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

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

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

Flow Document Content Reflow

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

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

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

Screenshot: Rendered FlowDocument example

В этом примере элемент управления 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, содержат отображаемые объекты.

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

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

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

Diagram: Flow content element class hierarchy

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

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

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

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

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

Paragraph

Paragraph обычно используется для группирования содержимого в абзац. Самый простой и распространенный способ использования класса 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 используется также как и тег <DIV> в HTML.

В приведенном ниже примере три абзаца определены в одном разделе 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 (например, 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>

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

Screenshot that shows a UIElement embedded in flow content.

Список

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, невозможно его использование в содержимом нефиксированного формата, если только он не содержится в 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 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="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>

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

Screenshot: Rendered Span example

InlineUIContainer

InlineUIContainer включает внедрение элементов UIElement (например, таких элементов управления, как Button) в элемент содержимого Inline. Этот элемент является встраиваемым аналогом для элемента BlockUIContainer, описанного выше. Ниж приводится пример использования InlineUIContainer для внедрения встраиваемого элемента Button в Paragraph.

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

Figure и Floater

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

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

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

Screenshot: Figure example

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="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>

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

Screenshot: LineBreak example

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

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

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

Таким образом, Run добавляется к InlineCollection из Paragraph. Этот подход аналогичен неявному использованию Run внутри объекта Paragraph в разметке:

<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 (блочный класс) для размещения своих дочерних элементов зависит от того, какой тип дочерних элементов (Block или Inline) может содержаться в родительском элементе. Правила включения для элементов размещения содержимого обобщаются в схеме содержимого в следующем разделе.

Примечание.

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

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

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

Diagram: Flow content containment schema

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

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

Diagram: RichTextBox containment rules

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

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

2. Согласно схеме, существует несколько элементов Block, которые можно выбрать, включая такие, как Paragraph, Section, Table, List и BlockUIContainer (см. блочные классы выше). Предположим, что нам нужен объект Table. Согласно приведенной выше схеме, объект Table содержит элемент TableRowGroup, который содержит элементы TableRow, которые содержат элементы TableCell, которые содержат объект, производный от Block. Ниже приведен соответствующий сегмент для Table, извлеченный из предыдущей схемы.

Diagram: Parent/child schema for Table

Ниже приводится соответствующая разметка.

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

3. Опять же, один или несколько элементов Block должно быть по структуре ниже элемента TableCell. Для удобства поместим часть текста в ячейку. Это можно сделать, использовав Paragraph вместе с Run. Ниже приводятся соответствующие фрагменты схемы, которые демонстрируют, что Paragraph может принимать элемент Inline, и что Run (элемент Inline) может принимать только неформатированный текст.

Diagram: Parent/child schema for Paragraph

Diagram: Parent/Child schema for Run

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

<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, предоставляемого рядом объектов, включая Inline, Paragraphи TextBlockTextBox.

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

<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

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

Screenshot: Text with default strikethrough effect

На рисунках ниже демонстрируются следующие варианты оформления текста: надчеркивание, нижняя линия и подчеркивание соответственно.

Screenshot: Overline TextDecorator

Screenshot: Default baseline effect on text

Screenshot: Text with default underline effect

Оформление текста

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

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

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

Screenshot showing text with altered typography.

Напротив, на следующем рисунке показано, как отрисовывается аналогичный пример с типографскими характеристиками по умолчанию.

Screenshot showing text with default typography.

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

См. также