Потоковые документы

194

Потоковый документ WPF создается с помощью сочетания потоковых элементов. Потоковые элементы существенно отличаются от элементов, с которыми вы имели дело до настоящего момента, тем, что они не являются наследниками знакомых вам классов UIElement и FrameworkElement. Они формируют совершенно отдельную ветвь классов, порожденных от ContentElement и FrameworkContentElement.

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

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

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

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

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

Элементы вывода содержимого

Элементы вывода содержимого делятся на две категории:

Блочные элементы

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

Строковые элементы

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

Модель содержимого позволяет строить несколько уровней вложения. К примеру, внутрь элемента Underline можно поместить элемент Bold, чтобы создать жирный подчеркнутый текст. Аналогично можно создать элемент Section, а внутри него несколько элементов Paragraph, каждый из которых содержит разнообразные строковые элементы с текстовым содержимым. Все эти элементы определены в пространстве имен System.Windows.Documents.

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

Если же вы очень хорошо знаете HTML, можете попробовать воспользоваться на удивление мощным транслятором из HTML в XAML, который доступен по адресу ссылка. Этот транслятор, реализованный на базе C#, позволяет использовать HTML-страницу в качестве заготовки потокового документа.

Форматирование элементов вывода содержимого

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

Базовые свойства форматирования для элементов вывода содержимого
Свойство Описание
Foreground и Background Принимают кисти, которые будут применяться для прорисовки текста переднего плана и фоновой поверхности. Свойство Background можно задать для объекта FlowDocument, содержащего всю разметку документа.
FontFamily, FontSize, FontStretch, FontStyle и FontWeight Позволяют точно настроить шрифт, используемый для вывода текста. Эти свойства можно задать для объекта FlowDocument, содержащего всю разметку документа.
ToolTip Позволяет задать всплывающую подсказку, которая будет появляться на экране при наведении указателя мыши на данный элемент. Можно указать текстовую строку или полный объект ToolTip.
Style Указывает стиль, который следует использовать для автоматического задания свойств элемента.
BorderBrush и BorderThickness Позволяют создать рамку, которая будет отображаться по краям элемента
Margin Задает промежуток между текущим элементом и его контейнером (или любыми соседними элементами). Если поле не задано, потоковые контейнеры добавят между блочными элементами и краями контейнера промежуток, по умолчанию равный 18 единицам. При желании можно явно задать меньшие промежутки.
А чтобы сократить пробел между двумя абзацами, потребуется уменьшить и нижнее поле первого абзаца, и верхнее поле второго абзаца. Если нужно уменьшить поля всех абзацев, попробуйте использовать стиль типа элемента, который действует на все абзацы.
Padding Задает отступ между краями и любыми вложенными элементами. По умолчанию равно О.
TextAlignment Задает горизонтальное выравнивание вложенного текстового содержимого (может принимать значения Left (влево), Right (вправо), Center (по центру) или Justify (по краям)). Обычно содержимое выравнивается по краям.
LineHeight Задает промежуток между строками во вложенном текстовом содержимом. Высота строки определяется в не зависящих от устройства пикселях. При отсутствии этого значения текст будет иметь одинарный промежуток, определяемый характеристиками используемого шрифта.
LineStackingStrategy Определяет промежуток между строками, содержащими шрифты разного размера. По умолчанию имеет значение MaxHeight: строка имеет такую высоту, как и самый высокий текст. Другое значение, BlockLineHeight, задает использование высоты из свойства LineHeight для всех строк, т.е. текст будет располагаться в соответствии с характеристиками шрифта абзаца. Если этот шрифт меньше самого большого шрифта в абзаце, то текст в некоторых строках может перекрываться. Если он имеет такой же размер или больше, то между некоторыми строками образуются дополнительные просветы.

Наряду со свойствами, описанными в этих двух таблицах, имеются еще некоторые дополнительные детали, которые можно указывать в отдельных элементах. Некоторые из них связаны с разбиением на страницы и колонки. Здесь мы упомянем следующие свойства:

TextDecorations

Это свойство имеется в элементах Paragraph и во всех элементах, порожденных от класса Inline. Оно принимает значения Strikethrough (зачеркивание), Overline (надчеркивание) или чаще Underline (подчеркивание).

Можно даже объединить эти значения, чтобы получить в тексте несколько линий сразу, хотя такое встречается редко.

Typography

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

Создание простого потокового документа

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

Потоковый документ создается с помощью класса FlowDocument. Visual Studio позволяет либо создать новый потоковый документ как отдельный файл, либо определить его внутри существующего окна, используя один из поддерживаемых контейнеров. Пока для создания потокового документа воспользуемся контейнером FlowDocumentScrollViewer. Ниже показан первоначальный вид разметки:

<Window x:Class="Wpf_Documents.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WPF Documents API" Height="390" Width="525">
    <FlowDocumentScrollViewer>
        <FlowDocument>
            ...
        </FlowDocument>
    </FlowDocumentScrollViewer>
</Window>

На данный момент не существует интерфейса WYSIWYG (What You See Is What You Get — что видишь, то и получаешь) для создания потоковых документов. Некоторые разработчики создают инструменты, которые могут преобразовывать файлы, написанные в Word 2007 XML (известном как WordML), в файлы XAML посредством разметки потокового документа. Однако такие средства не готовы к массовому производству. А пока можно создать простой текстовый редактор с помощью элемента управления RichTextBox и использовать его для создания содержимого потокового документа.

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

<FlowDocumentScrollViewer>
        <FlowDocument>
            <Paragraph>Hello, world!</Paragraph>
            <Paragraph>Это первый абзац</Paragraph>
        </FlowDocument>
</FlowDocumentScrollViewer>

На рисунке представлен результат:

Заготовка потокового документа

Линейка прокрутки добавляется автоматически. Шрифт (Segoe UI) выбирается из системных настроек Windows, а не из вмещающего окна.

Обычно элемент FlowDocumentScrollViewer позволяет выделять текст (как в веб-браузере). Таким образом пользователь может копировать части документа в буфер обмена Windows и вставлять их в другие приложения. Если это нежелательно, присвойте свойству FlowDocumentScrollViewer.IsSelectionEnabled значение false.

Пройди тесты
Лучший чат для C# программистов