Логические и визуальные деревья

42

При вводе XAML-разметки в Visual Studio 2010, Expression Blend либо таком инструменте, как Kaxaml, разметка становится логическим представлением документа XAML. Точно также, при написании кода C#, добавляющего новые элементы к элементу управления StackPanel, новые элементы вставляются в логическое дерево. По сути, логическое представление показывает, как содержимое будет позиционировать внутри различных диспетчеров компоновки для главного окна (или другого корневого элемента, такого как Page или NavigationWindow).

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

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

Логически Button остается типом Button, и поддерживает все свойства, методы и события, как и ожидалось. Но визуально элемент получает совершенно новый внешний вид. Один этот факт делает WPF исключительно удобным API-интерфейсом, учитывая, что другие инструментарии потребовали бы в такой ситуации построения совершенно нового класса, представляющего звездообразную кнопку. В WPF достаточно определить новую разметку.

Рассмотрим исключительно простое окно с двумя кнопками. Чтобы создать это окно, элемент управления StackPanel вкладывается внутрь Window. В StackPanel помещаются два элемента управления Button, а внутрь каждого Button можно добавить некоторое содержимое по своему выбору (в данном случае — две строки). Вот необходимая для этого разметка:

<StackPanel Margin="5">
   <Button Padding="5">Первая кнопка</Button>
   <Button Padding="5">Вторая кнопка</Button>
</StackPanel>

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

Логическое дерево

Однако в настройке элементов логическое дерево мало помогает. Очевидно, можно было бы заменить целый элемент другим элементом (например, подставить специальный класс FancyButton вместо текущего Button), но это потребовало бы больше работы и могло разрушить интерфейс приложения или его код. По этой причине в WPF предлагается визуальное дерево.

Визуальное дерево — это расширенная версия логического дерева. Оно разбивает элементы на более мелкие части. Другими словами, вместо тщательно инкапсулированного черного ящика, такого как элемент управления Button, вы видите визуальные компоненты этой кнопки — рамку, которая обеспечивает кнопкам узнаваемый текстурированный фон (представленный классом ButtonChrome), контейнер внутри (ContentPresenter) и блок, хранящий текст кнопки (представленный знакомым классом TextBlock). На рисунке показана схема визуального дерева для окна из примера:

Визуальное дерево

Все эти детали сами по себе являются элементами. Другими словами, каждая индивидуальная деталь такого элемента управления, как Button, представлена классом, унаследованным FrameworkElement.

Важно понимать, что существует более одного возможного расширения логического дерева в визуальное дерево. Такие детали, как используемые стили, установленные свойства, операционная система (Windows ХР или Windows 7/Vista), а также текущая тема Windows, могут влиять на способ отображения визуального дерева. Например, в предыдущем примере кнопка включает текстовое содержимое, в результате чего автоматически создает вложенный элемент TextBlock. Но, как известно, элемент управления Button — это элемент с содержимым, и потому может иметь внутри себя любой другой элемент, который вы пожелаете в него вставить.

Пока все должно быть ясно. Было показано, что элементы WPF можно разбирать на меньшие части. Но какое преимущество это дает разработчику WPF? Визуальное дерево позволяет делать две полезные вещи.

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