Поделиться через


Деревья в WPF

Обновлен: Ноябрь 2007

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

В этом разделе содержатся следующие подразделы.

  • Деревья в WPF
  • Логическое дерево
  • Визуальное дерево
  • Деревья, элементы содержимого и узлы содержимого
  • Прохождение по дереву
  • Маршруты для маршрутизируемых событий как «дерево»
  • Ресурсы и деревья
  • Связанные разделы

Деревья в WPF

Первичной структурой дерева в WPF является дерево элементов. При создании страницы приложения в XAML дерево создается на основе отношений вложенности элементов в разметке. При создании приложения в коде дерево создается в зависимости от того, как назначаются значения для свойств, которые представляют модель содержимого для данного элемента. В Windows Presentation Foundation (WPF) на самом деле существует два способа обработки и концептуализации дерева элементов: в качестве логического дерева и в качестве визуального дерева. Различия между логическими деревьями и визуальными деревьями не всегда важны, но иногда они могут вызвать проблемы с некоторыми подсистемами WPF и повлиять на изменения, внесенные в разметку или код.

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

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

В WPF добавление содержимого в элементы происходит с помощью свойств. Например, можно добавить элементы в элемент управления ListBox с помощью его свойства Items. При этом элементы помещаются в ItemCollection элемента управления ListBox. Чтобы добавить элементы в DockPanel, используется его свойство Children. Здесь происходит добавление элементов в UIElementCollection элемента управления DockPanel. Пример кода см. в разделе Практическое руководство. Динамическое добавление элемента.

В Язык XAML (Extensible Application Markup Language) при помещении элементов списка в ListBox или элементов управления и других элементов в DockPanel можно также использовать свойства Items и Children, явным или неявным образом, как показано в следующем примере.

<DockPanel
  Name="ParentElement"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >

  <!--implicit: <DockPanel.Children>-->
  <ListBox DockPanel.Dock="Top">
    <!--implicit: <ListBox.Items>-->
    <ListItem>
      <Paragraph>Dog</Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>Cat</Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>Fish</Paragraph>
    </ListItem>
    <!--implicit: </ListBox.Items>-->
  </ListBox>
  <Button Height="20" Width="100" DockPanel.Dock="Top">Buy a Pet</Button>

  <!--implicit: </DockPanel.Children>-->
</DockPanel>

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

Схематическое изображение универсального логического дерева
Схема дерева

Назначение логического дерева

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

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

Переопределение логического дерева

Авторы дополнительных элементов управления могут переопределить логическое дерево, переопределив несколько API-интерфейсы, которые определяют то, как основная модель объекта или содержимого добавляет или удаляет элементы логического дерева. Пример переопределения логического дерева содержится в разделе Как переопределить логическое дерево.

Наследование значения свойства

Наследование значения свойств действует через гибридное дерево. Фактические метаданные, содержащие свойствоInherits, позволяющее наследование свойств, является классом FrameworkPropertyMetadataуровня платформы WPF. Таким образом, и родительский элемент, содержащий исходное значение, и наследующий дочерний элемент, должны быть FrameworkElement или FrameworkContentElement, и оба должны быть частью некоторого логического дерева. Однако, логическое дерево родительского элемента, в отличии от дочернего, может быть несвязанным, с наследованием значения свойства, способного принять промежуточный визуальный элемент, которого нет в логическом дереве. Чтобы наследование значения свойств могло постоянно функционировать с такими ограничениями, наследуемое свойство должно быть зарегистрировано как вложенное свойство зависимостей. Точное дерево, используемое для наследования свойств, не может быть полностью предсказано вспомогательным служебным методом класса даже во время выполнения. Дополнительные сведения см. в разделе Наследование значения свойства.

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

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

Деревья, элементы содержимого и узлы содержимого

Элементы содержимого (классы, производные от ContentElement) не являются частью визуального дерева; они не наследуют от Visual и не имеют визуального представления. Чтобы полностью отобразиться в пользовательском интерфейсе, ContentElement должен быть расположен в узле содержимого, который одновременно является и Visual, и элементом логического дерева, обычно, FrameworkElement. Можно представить узел содержимого в качестве «обозревателя» содержимого, который выбирает способ отображения содержимого в пределах области экрана, управляемой узлом. При размещении содержимого оно может стать участником некоторых процессов дерева, которые обычно связаны с визуальным деревом. Как правило, узловой класс FrameworkElement содержит код реализации, в котором любой размещенный ContentElement добавляется к маршруту события через подузлы логического дерева содержимого, даже если размещенное содержимое не является частью действительного визуального дерева. Это необходимо для того, чтобы ContentElement мог получить маршрутизируемое событие, которое маршрутизирует к любому элементу, кроме самого себя.

Прохождение по дереву

Класс LogicalTreeHelper предоставляет методы GetChildren, GetParent и FindLogicalNode для прохождения по логическому дереву. В большинстве случаев не следует проходить по логическому дереву существующих элементов управления, так как эти элементы управления почти всегда предоставляют логические дочерние элементы в качестве выделенного свойства коллекции, которое поддерживает API-интерфейсы коллекции (например, Add, индексатор и т.д.). Обход дерева обычно используется авторами элемента управления, которые отказались от создания элементов управления, производных от предполагаемых шаблонов элемента управления, например, ItemsControl или Panel, где свойства коллекции уже определены, и которые планируют поддержку собственных свойств коллекции.

Визуальное дерево также поддерживает вспомогательный класс для прохождения визуального дерева — VisualTreeHelper. Визуальное дерево не так удобно предоставляется из свойств определенного элемента управления. Таким образом, класс VisualTreeHelper является рекомендуемым способом прохода визуального дерева, если это необходимо для программного сценария. Дополнительные сведения см. в разделе Обзор графической визуализации Windows Presentation Foundation.

Маршруты для маршрутизируемых событий как «дерево»

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

Ресурсы и деревья

Поиск ресурсов обычно затрагивает основное логическое дерево. Объекты, которые не входят в логическое дерево, могут ссылаться на ресурсы, но поиск начинается с той точки, где объект подключен к логическому дереву. Только узлы логического дерева могут иметь свойство Resources, содержащее ResourceDictionary. Таким образом, это означает отсутствие преимущества при обходе визуального дерева для поиска ресурсов.

В то же время поиск ресурсов также можно расширить за пределы логического дерева. Для разметки приложения поиск ресурса можно затем продолжить в ресурсах приложения, поддержке тем и в системных значениях. Сами темы также могут ссылаться на системные значения вне логического дерева тем, если ссылки на ресурсы являются динамическими. Дополнительные сведения о ресурсах и логике поиска см. в разделе Общие сведения о ресурсах.

См. также

Основные понятия

Общие сведения о входных данных

Обзор графической визуализации Windows Presentation Foundation

Общие сведения о перенаправленных событиях

Инициализация для элементов типа Object вне дерева элементов

Архитектура WPF