Программное взаимодействие с элементами
51WPF --- Периферия WPF --- Программное взаимодействие с элементами
Пока мы имели дело с примерами создания разметки, необходимой для потоковых документов. Но вас не должен удивлять тот факт, что потоковые документы можно создавать и программно. (Ведь именно это и делает компилятор XAML при чтении разметки вашего потокового документа.)
Программная генерация потокового документа — довольно утомительное занятие, т.к. необходимо создавать множество различных элементов. Приходится вручную создавать каждый элемент XAML, а затем устанавливать его свойства, ведь ни один конструктор не сделает это за вас. Понадобится также создавать элементы Run для упаковки каждой порции текста, так как они не будут создаваться автоматически.
Ниже приведен фрагмент кода, который создает документ с одним абзацем, часть текста в котором выделена жирным шрифтом. Затем он выводит документ в существующем контейнере FlowDocumentScrollViewer с именем docViewer:
// Создание первой части фразы.
Run runFirst = new Run();
runFirst.Text = "Привет всем от ";
// Создание жирного текста.
Bold bold = new Bold();
Run runBold = new Run();
runBold.Text = "динамически генерируемых";
bold.Inlines.Add(runBold);
// Создание последней части фразы.
Run runLast = new Run();
runLast.Text = " документов";
// Добавление трех частей фразы в абзац по порядку.
Paragraph paragraph = new Paragraph();
paragraph.Inlines.Add(runFirst);
paragraph.Inlines.Add(bold);
paragraph.Inlines.Add(runLast);
// Создание документа и добавление в него этого абзаца.
FlowDocument document = new FlowDocument();
document.Blocks.Add(paragraph);
// Вывод документа.
docViewer.Document = document;
Чаще всего вы не будете создавать потоковые документы программно. Однако может понадобиться создать приложение, которое будет просматривать части потокового документа и динамически изменять их. Это можно сделать точно так же, как и при взаимодействии с любыми другими элементами WPF реагируя на события элементов и назначая имена элементам, которые нужно будет изменять. Однако в потоковых документах используется глубокое вложение содержимого неизвестной заранее структуры, и возможно, придется пробраться через несколько уровней, чтобы найти нужное содержимое. (Имейте в виду, что содержимое всегда хранится в элементе Run, даже если он не объявлен явным образом.)
В перемещении по структуре потокового документа вам помогут несколько приемов:
Чтобы добраться до блочных элементов в потоковом документе, используйте коллекцию FlowDocument.Blocks. Для перехода к первому или последнему блочному элементу имеются конструкции FlowDocument.Blocks.FirstBlock или FlowDocument.Blocks.LastBlock.
Чтобы перейти от одного блочного элемента к следующему (или предыдущему) блоку, используйте свойство Block.NextBlock (или Block.PreviousBlock). Можно также использовать коллекцию Block.SiblingBlocks для просмотра всех блочных элементов, находящихся на одном уровне.
Многие блочные элементы могут содержать другие элементы. Например, элемент List содержит коллекцию ListItem, элемент Section — коллекцию Blocks, a Paragraph — коллекцию Inlines.
Если требуется изменить текст внутри потокового документа, то лучше всего выделить именно ту часть, которую нужно изменить (и не больше), с помощью элемента Span.
Вы, видимо, уже заметили, что текстовое содержимое в потоковом документе по умолчанию выравнивается так, что каждая строка растягивается от левого поля до правого. Это поведение можно изменить с помощью свойства TextAlignment, однако большинство потоковых документов в WPF выровнены по ширине.
Чтобы улучшить читаемость выровненного по ширине текста, можно воспользоваться оптимальной компоновкой абзаца, которая распределяет пробелы максимально равномерно. Она позволяет избежать появления отвлекающих внимание "змеек" пробелов и неравномерно расставленных слов, что бывает в случае применения упрощенных алгоритмов выравнивания строк (например, используемых в веб-браузерах).
Простые алгоритмы выравнивания строк работают построчно. Оптимальная компоновка абзацев в WPF использует алгоритм тотального заполнения, который анализирует и последующие строки. Он выбирает такие разрывы строк, которые равномерно распределяют слова во всем абзаце, что в итоге дает оптимальный результат для всех строк.
Обычно функция оптимальной компоновки абзаца не используется — наверно, из-за повышенной сложности алгоритма тотального заполнения. Однако в большинстве случаев отклик приложений (т.е. его поведение при изменении размера окна) такой же, как и при включенной оптимальной компоновке абзацев.
Чтобы активизировать оптимальную компоновку абзацев, нужно присвоить свойству FlowDocument.IsOptimalParagraphEnabled значение true.
Чтобы еще улучшить выравнивание текста, особенно в узких окнах, присвойте свойству FlowDocument.IsHyphenationEnabled значение true. Тогда WPF будет разрывать длинные слова там, где это необходимо, чтобы обеспечить небольшое расстояние между словами. Переносы слов хорошо уживаются с оптимальным заполнением абзацев и особенно важны при отображении в несколько колонок. WPF использует словарь переноса слов (английского языка), чтобы правильно вставлять дефисы (между слогами — например, "algo-rithm", а не "algori-thm).