В предыдущих главах для вывода текста использовался элемент TextBlock. Однако этого элемента недостаточно для создания насыщенных приложений с большими объемами текста со сложным форматированием и встроенными изображениями. Для этого нам надо использовать документы.
Итак, все документы в WPF деляться на две группы:
Фиксированные документы (fixed documents). Формат и расположение содержимого таких документов фиксировано и не может быть изменено. На различных устройствах с различным разрешением экрана содержимое будет выглядеть одинаково и не будет оптимизировано. Такие документы преимущественно предназначены для печати. Для фиксированных документов WPF использует стандарт XPS (XML Paper Specification)
Потоковые документы (flow documents). Эти документы предназначены для просмотра на экране монитора. А WPF выполняет оптимизацию документа под конкретные параметры среды.
Потоковые документы в WPF представлены классом FlowDocument, который может включать в себя разлиные потоковые элементы (flow elements). Все эти элементы не являются стандартными элементами управления, как, например, Button или TextBlock, а наследуются от базового класса FrameworkContentElement и поэтому поддерживают такие механизмы, как привязка, анимация и другие, но не используют компоновку. В итоге всю иерархию потоковых элементов можно представить следующим образом:
Для использования объекта FlowDocument мы должны поместить его в один из контейнеров - FlowDocumentReader, FlowDocumentPageViewer или FlowDocumentScrollViewer. Например:
<FlowDocumentScrollViewer> <FlowDocument> <Paragraph>Hello World!</Paragraph> <Paragraph>22.05.1984</Paragraph> </FlowDocument> </FlowDocumentScrollViewer>
В качестве содержимого FlowDocument принимает один или несколько потоковых элементов. Все эти элементы являются наследниками класса TextElement и могут быть блочными (block) и строчными (inline).
К блочным элементам относят следующие : Paragraph, List, Table, BlockUIContainer и Section.
Элемент Paragraph содержит коллекцию Inlines, которая в свою очередь включает строковые элементы, причем не только текст. Чтобы параграф отображал текст, надо использовать строчный элемент Run:
<Paragraph x:Name="p1" TextIndent="20"> <Run>Hello World!</Run> </Paragraph>
Хотя мы можем не использовать Run и напрямую писать текст в содержимое параграфа, однако в этом случае элемент Run все равно будет создан, только неявно. Поэтому чтобы в данном случае получить в коде содержимое параграфа, нам надо получить текст элемента Run:
string s = ((Run)p1.Inlines.FirstInline).Text;
Блочный элемент List представляет собой список. Он содержит коллекцию элементов ListItem, которые и представляют элементы списка. Каждый из элементов ListItem, в свою очередь, может включать другие блочные элементы, например, Paragraph:
<FlowDocumentScrollViewer > <FlowDocument> <Paragraph>Флагманы 2015</Paragraph> <List MarkerStyle="Box"> <ListItem> <Paragraph>Lumia 950 XL</Paragraph> </ListItem> <ListItem> <Paragraph>iPhone 6S Plus</Paragraph> </ListItem> <ListItem> <Paragraph>Galaxy S6 Edge</Paragraph> </ListItem> <ListItem> <Paragraph>Nexus 6P</Paragraph> </ListItem> </List> </FlowDocument> </FlowDocumentScrollViewer>
С помощью свойства MarkerStyle можно задать формат списка:
Disc
: стандартный черный кружочек. Значение по умолчанию
Box
: черный квадратик, как в примере выше
Circle
: кружок без наполнения
Square
: квадратик без наполнения
Decimal
: десятичные цифры от 1, то есть обычный нумерованный список
LowerLatin
: строчные латинские буквы (a, b, c)
UpperLatin
: заглавные латинские буквы (A, B, C)
LowerRoman
: латинские цифры в нижнем регистре (i, iv, x)
UpperRoman
: латинские цифры в верхнем регистре (I, IV, X)
None
: отсутствие маркера списка
Элемент Table организует вывод содержимого в виде таблицы. Он имеет вложенный элемент TableRowGroup. Этот элемент позволяет задать однообразный вид таблицы и содержит коллекцию строк - элементов TableRow (строку таблицы). А каждый элемент TableRow содержит несколько элементов TableCell (ячейка таблицы). В элементе TableCell затем уже размещаются блочные элементы с содержимым, например, элементы Paragraph:
<FlowDocumentScrollViewer > <FlowDocument> <Paragraph>Флагманы 2015</Paragraph> <Table> <Table.Columns> <TableColumn Width="2*" /> <TableColumn Width="2*" /> <TableColumn Width="*" /> </Table.Columns> <TableRowGroup FontSize="14"> <TableRow FontSize="15"> <TableCell> <Paragraph>Модель</Paragraph> </TableCell> <TableCell> <Paragraph>Компания</Paragraph> </TableCell> <TableCell> <Paragraph>Цена</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>Lumia 950</Paragraph> </TableCell> <TableCell> <Paragraph>Microsoft</Paragraph> </TableCell> <TableCell> <Paragraph>45000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>iPhone 6s</Paragraph> </TableCell> <TableCell> <Paragraph>Apple</Paragraph> </TableCell> <TableCell> <Paragraph>54000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>Nexus 6P</Paragraph> </TableCell> <TableCell> <Paragraph>Huawei</Paragraph> </TableCell> <TableCell> <Paragraph>50000</Paragraph> </TableCell> </TableRow> </TableRowGroup> </Table> </FlowDocument> </FlowDocumentScrollViewer>
Для определения столбцов в элементе применяется коллекция Table.Columns
. Каждый столбец представляет элемент TableColumn, у которого мы можем задать ширину.
Элемент Section предназначен для группировки других блочных элементов и предназначен прежде всего для однобразной стилизации этих элементов:
<FlowDocument> <Section FontSize="16"> <Paragraph>Флагманы 2016</Paragraph> <Paragraph>Xiaomi Mi5</Paragraph> <Paragraph>Samsung Galaxy S7</Paragraph> <Paragraph>HP Elite X3</Paragraph> </Section> </FlowDocument>
Элемент BlockUIContainer позволяет добавить в документ различные элементы управления, которые не являются блочными или строчными элементами. Так, мы можем добавить кнопку или картинку к документу. Такая функциональность особенно полезна, когда необходимо добавить интерактивную связь с пользователем:
<FlowDocument> <Paragraph TextAlignment="Center">TIOBE Rate</Paragraph> <BlockUIContainer FontSize="13"> <StackPanel Orientation="Vertical"> <TextBlock Height="40" Padding="10">Click the Button to see TIOBE Rate</TextBlock> <Button Width="60">Click Me</Button> </StackPanel> </BlockUIContainer> </FlowDocument>
Выше мы уже использовали элемент Run, который хранит некоторый текст, выводимый в блочном элементе, например, в элементе Paragraph.
Элемент Span объединяет другие строчные элементы и применяет ним определенное форматирование:
<FlowDocument> <Paragraph> <Span Background="Red"> <Run>This is a WPF Application!</Run> <Run>WPF is cool</Run> </Span> </Paragraph> </FlowDocument>
Чтобы задать для текста отдельные способы форматирования, применяются элементы Bold,Italic и Underline, которые позволяют создать текст полужирным шрифтом, курсивом и подчеркнутый текст соответственно.
<FlowDocument> <Paragraph> <Span Background="Wheat"> <Italic>This is a WPF Application!</Italic> <Bold>WPF is cool!</Bold> <Underline>Great App</Underline> </Span> </Paragraph> </FlowDocument>
Элемент Hyperlink позволяет вставить в документ ссылку для перехода и может использоваться в навигационных приложениях:
<Paragraph> <Hyperlink NavigateUri="http:\\microsoft.com">Microsoft</Hyperlink> </Paragraph>
Элемент LineBreak задает перевод строки:
<FlowDocument> <Paragraph> <Run>Перевод</Run> <LineBreak /> <Run>на другую строку</Run> </Paragraph> </FlowDocument>
InlineUIContainer подобен элементу BlockUIContainer и также позволяет помещать другие элементы управления, например, кнопки, только является строковым.
Элементы Floater и Figure позволяют вывести плавающее окно с некоторой информацией, текстом, картинками и прочим:
<FlowDocument> <Paragraph TextAlignment="Left" FontSize="15"> "Да, здесь, в этом лесу был этот дуб, с которым мы были согласны", подумал князь Андрей. <Floater Width="170" Padding="5" HorizontalAlignment="Left" FontSize="18" FontStyle="Italic"> <Paragraph>Война и мир. Том 2. Часть 3</Paragraph> </Floater> "Да где он", подумал опять князь Андрей, глядя на левую сторону дороги и сам того не зная, не узнавая его... </Paragraph> </FlowDocument>
Остальной текст будет обтекать элемент Floater, заданный таким образом, справа.
Figure во многом аналогичен элементу Floater за тем исключением, что дает больше возможностей по контролю за позиционированием. Так, следующая разметка будет создавать эффект, аналогичный примеру с Floater:
<FlowDocument> <Paragraph TextAlignment="Left" FontSize="15"> "Да, здесь, в этом лесу был этот дуб, с которым мы были согласны", подумал князь Андрей. <Figure Width="170" Padding="5" HorizontalAnchor="ContentLeft" FontSize="18" FontStyle="Italic"> <Paragraph>Война и мир. Том 2. Часть 3</Paragraph> </Figure> "Да где он", подумал опять князь Андрей, глядя на левую сторону дороги и сам того не зная... </Paragraph> </FlowDocument>
С помощью свойства HorizontalAnchor мы можем управлять позиционированием элемента по горизонтали. Так, значение
ContentLeft
позволяет выравнить текст по левой стороне, ContentRight
- по правой стороне, а значение ContentCenter
- по центру.
Другое свойство VerticalAnchor позволяет выравнить содержимое Figure по вертикали.