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


VisualTreeHelper Класс

Определение

Предоставляет служебные методы, которые можно использовать для обхода отношений объектов (вдоль осей дочерних и родительских или родительских объектов) в визуальном дереве приложения.

public ref class VisualTreeHelper sealed
/// [Windows.Foundation.Metadata.ContractVersion(Windows.Foundation.UniversalApiContract, 65536)]
/// [Windows.Foundation.Metadata.MarshalingBehavior(Windows.Foundation.Metadata.MarshalingType.Agile)]
/// [Windows.Foundation.Metadata.Threading(Windows.Foundation.Metadata.ThreadingModel.Both)]
class VisualTreeHelper final
[Windows.Foundation.Metadata.ContractVersion(typeof(Windows.Foundation.UniversalApiContract), 65536)]
[Windows.Foundation.Metadata.MarshalingBehavior(Windows.Foundation.Metadata.MarshalingType.Agile)]
[Windows.Foundation.Metadata.Threading(Windows.Foundation.Metadata.ThreadingModel.Both)]
public sealed class VisualTreeHelper
Public NotInheritable Class VisualTreeHelper
Наследование
Object Platform::Object IInspectable VisualTreeHelper
Атрибуты

Требования к Windows

Семейство устройств
Windows 10 (появилось в 10.0.10240.0)
API contract
Windows.Foundation.UniversalApiContract (появилось в v1.0)

Примеры

Ниже приведен пример служебной функции, которая может копировать список дочерних элементов определенного типа из визуального дерева. В нем используются базовые методы обхода GetChildrenCount и GetChild. Он использует рекурсию, чтобы элементы можно было найти независимо от уровня вложенности в промежуточных контейнерах. Он также использует метод расширения IsSubclassOf из System.Reflection , который расширяет сравнение типов, чтобы рассматривать подтипы как совпадение для типа.

internal static void FindChildren<T>(List<T> results, DependencyObject startNode)
  where T : DependencyObject
{
    int count = VisualTreeHelper.GetChildrenCount(startNode);
    for (int i = 0; i < count; i++)
    {
        DependencyObject current = VisualTreeHelper.GetChild(startNode, i);
        if ((current.GetType()).Equals(typeof(T)) || (current.GetType().GetTypeInfo().IsSubclassOf(typeof(T))))
        {
            T asType = (T)current;
            results.Add(asType);
        }
        FindChildren<T>(results, current);
    }
}

Комментарии

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

Цель класса VisualTreeHelper — помочь с обнаружением объектов, которые вы ищете в дереве среды выполнения объектов, но для вашего сценария нет более прямого API отношений между объектами. Иногда вы не знаете точный тип или имя объекта. Или, возможно, вы знаете, что определенный объект отображается где-то в дереве, но вы не знаете точное положение. Для таких сценариев VisualTreeHelper полезен, так как вы можете рекурсивно найти все объекты в визуальном дереве, а затем просмотреть этот набор и найти совпадение на основе ваших критериев.

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

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

Разметка XAML и визуальное дерево не соответствуют точно node-for-node, так как XAML предназначен для разметки и простоты использования во время определения разметки, поэтому иногда он содержит дополнительные элементы. Например, XAML содержит элементы свойств, которые задают значения свойств, если один элемент найден вложенным внутри другого. В визуальном дереве это будет просто выглядеть как свойство объекта, задается другим объектом. XAML также имеет концепцию свойства содержимого, где заданное свойство не обозначается явным образом в разметке. Дополнительные сведения о конкретной терминологии и правилах для XAML см. в статье Общие сведения о XAML.

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

Как правило, вы объединяете несколько вызовов API VisualTreeHelper для написания собственных вспомогательных функций, которые исследуют визуальное дерево способами, характерными для сценариев вашего приложения.

Обход визуального дерева

Обход дерева объектов (иногда известный в разговоре как ходьба по дереву) является распространенным методом в объектных моделях. Используются свойства, которые ссылаются на дочерние объекты (обычно это коллекции) или родительские связи с содержащимся объектом (обычно это делается из коллекции и возвращает саму коллекцию). В качестве грубого описания процесса вы вызываете последовательность дочерних свойств и родительских свойств или, возможно, вспомогательные методы для навигации по осям дерева объектов, пока не получите значение, содержащее искомый объект. Как правило, вы должны иметь возможность создавать содержимое в XAML таким образом, чтобы не было необходимости запрашивать структуру дерева. Чтобы избежать необходимости обхода дерева, следует присвоить элементам XAML значение атрибута x:Name / Name в создаваемой разметке XAML. Это создает немедленную ссылку, доступную для доступа к коду во время выполнения, и это гораздо менее подверженный ошибкам метод получения ссылок на объекты, чем переход по дереву. Кроме того, если вы создаете объекты с помощью кода, а не XAML, следует объявить частные поля или переменные, которые сохраняют ссылку на объект во время выполнения. Обычно нет необходимости проходить по дереву, чтобы найти объекты, созданные в собственном коде.

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

Обход дерева вниз (вдали от корня) нескольких уровней можно выполнить с помощью GetChildrenCount для ненулевых значений, а затем GetChild для запроса определенного индекса. При попытке привести элементы в качестве определенных подтипов UIElement может потребоваться использовать метод try/catch или эквивалент. Как правило, API VisualTreeHelper возвращает элементы в виде DependencyObject , и его необходимо привести, чтобы сделать что-нибудь полезное (даже для такой простой операции, как проверка его значения Name ).

Примечания для предыдущих версий

Windows 8

Потоки пользовательского интерфейса

Windows 8 разрешены вызовы функций VisualTreeHelper, которые ссылались на объекты в неправильном (а не текущем) потоке пользовательского интерфейса. Начиная с Windows 8.1 функция создает исключение, если она не вызывается из текущего потока пользовательского интерфейса. Учет этого нового поведения должен быть очень необычным сценарием миграции приложений; В первую очередь трудно получить элементы пользовательского интерфейса в разных потоках.

Приложения, которые были скомпилированы для Windows 8, но выполнялись на Windows 8.1, используют поведение Windows 8.1 и будут вызываться специально при вызове функции VisualTreeHelper, а не в коде нижестоящего приложения, использующем объект между потоками.

Пользовательский интерфейс приложения для экранной клавиатуры

Windows 8 имеет внутреннюю логику, которая связывает ScrollViewer с общим пользовательским интерфейсом приложения каждый раз, когда пользователь вызывает экранную клавиатуру. Эта экранная клавиатура — это специальная функция специальных возможностей, которую пользователи запрашивают через Центр специальных возможностей. Это не то же самое, что и мягкая клавиатура, которая может отображаться в пользовательском интерфейсе приложения для элементов управления вводом текста, если система не обнаруживает устройства клавиатуры. Внутренний ScrollViewer делает это для того, чтобы можно было прокручивать область, где находится приложение, если прокрутка выполняется принудительно, так как клавиатура занимает место в пользовательском интерфейсе.

Начиная с Windows 8.1, система по-прежнему имеет поведение пользовательского интерфейса или макета при появлении экранной клавиатуры, но она больше не использует этот внутренний ScrollViewer. Вместо этого используется выделенный внутренний элемент управления, который код приложения не может изменить или проверить.

Большинство аспектов этого изменения поведения вообще не влияют на приложения. Однако ваше приложение могло предвидеть такое поведение, предоставив неявный стиль для ScrollViewer , предназначенный для изменения макета, или пройдя по дереву с помощью VisualTreeHelper, чтобы найти этот внутренний ScrollViewer и изменить его во время выполнения. Для приложения, скомпилированного для Windows 8.1 этот код не будет полезен.

Приложения, которые скомпилированы для Windows 8, но выполняются в Windows 8.1, продолжают использовать правила, действующие в Windows 8.

Журнал версий

Версия Windows Версия пакета SDK Добавленная стоимость
1903 18362 GetOpenPopupsForXamlRoot

Методы

DisconnectChildrenRecursive(UIElement)

Явно удаляет все ссылки из целевого элемента UIElement с целью очистки циклов ссылок.

FindElementsInHostCoordinates(Point, UIElement, Boolean)

Извлекает набор объектов, расположенных в указанной точке координат x-y пользовательского интерфейса приложения. Набор объектов представляет компоненты визуального дерева, которые имеют общую точку.

FindElementsInHostCoordinates(Point, UIElement)

Извлекает набор объектов, расположенных в указанной точке координат x-y пользовательского интерфейса приложения. Набор объектов представляет компоненты визуального дерева, которые имеют общую точку.

FindElementsInHostCoordinates(Rect, UIElement, Boolean)

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

FindElementsInHostCoordinates(Rect, UIElement)

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

GetChild(DependencyObject, Int32)

Используя предоставленный индекс, получает определенный дочерний объект предоставленного объекта путем изучения визуального дерева.

GetChildrenCount(DependencyObject)

Возвращает количество дочерних элементов, существующих в дочерней коллекции объекта в визуальном дереве.

GetOpenPopups(Window)

Извлекает коллекцию всех открытых всплывающих элементов управления из целевого окна.

GetOpenPopupsForXamlRoot(XamlRoot)

Извлекает коллекцию всех открытых всплывающих элементов управления из целевого объекта XamlRoot.

GetParent(DependencyObject)

Возвращает родительский объект объекта в визуальном дереве.

Применяется к

См. также раздел