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 中引入)

示例

下面是一个实用工具函数的示例,该函数可以从可视化树中复制特定类型的子元素的列表。 它使用基本遍历方法 GetChildrenCountGetChild。 它使用递归,以便无论中间容器中的嵌套级别是什么,都可以找到元素。 它还使用 System.Reflection 中的 IsSubclassOf 扩展方法,该方法扩展了类型比较,以将子类型视为 Type 的匹配项。

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 标记和可视化树与节点对节点不完全匹配,因为 XAML 专为标记设计,在标记定义期间易于使用,因此它有时具有额外的元素。 例如,XAML 具有属性元素,如果发现一个元素嵌套在另一个元素中,则会设置属性值。 在可视化树中,这看起来就像是另一个对象设置的对象上的属性。 XAML 还具有内容属性的概念,其中设置的属性未在标记中显式指定。 有关 XAML 的特定术语和规则的详细信息,请参阅 XAML 概述

可视化树在内部用于 UI 呈现过程,但了解可视化树的结构对于某些方案非常重要,例如编写或替换控件模板,或在运行时分析控件的结构和部件。 对于这些方案,Windows 运行时提供了 VisualTreeHelper API,该 API 可以更通用的方式检查可视化树。 (理论上,也可以使用特定于对象的父属性和子属性构造此类树,但必须确切地知道每个元素支持哪些属性,这很难发现或管理。)

通常结合多个 VisualTreeHelper API 调用来编写自己的帮助程序函数,这些函数以特定于你自己的应用方案的方式调查可视化树。

遍历可视化树

遍历对象树 (有时通俗地称为遍 历树) 是对象模型中的一种常见技术。 使用引用子对象的属性 (这些属性通常是集合) 或包含对象的父关系 (这通常是从集合中完成的,并返回集合本身) 。 作为该过程的粗略说明,可以调用一系列子属性和父属性(或可能帮助程序方法)来导航对象树的轴,直到检索包含要查找的对象的值。 一般情况下,你应该能够在 XAML 中构造内容,这样就不需要广泛查询树的结构。 为了避免需要遍历树,应在创建它们的 XAML 标记中为 XAML 元素提供 x:Name / Name 属性的值。 这会创建一个可用于运行时代码访问的即时引用,并且与遍过树相比,获取对象引用的易出错技术要少得多。 或者,如果要通过代码而不是 XAML 创建对象,则应声明在运行时保留对象引用的私有字段或变量。 通常无需遍历树来查找在你自己的代码中创建的对象。

但是,在某些情况下,为对象指定名称并将对象引用保留在范围内是不可能或不切实际的。 其中一种情况是,如果要添加由用户提供或由数据绑定提供的动态内容,或者使用视图模型和业务对象。 在这些情况下,不能始终预测添加的项数或控件及其子级的结构。 另一种方案是检查控件的应用模板,或者控件或演示者内容的复合部分。

将树向下遍历 (远离根) 可以使用 GetChildrenCount 获取非零值,然后使用 GetChild 请求特定索引。 如果尝试将元素强制转换为特定的 UIElement 子类型,则可能必须使用 try/catch 技术或等效技术。 通常,VisualTreeHelper API 将元素作为 DependencyObject 返回,并且你需要对其进行强制转换,以便执行任何有用的 (即使是像检查其 Name 值) 一样简单的操作。

早期版本的说明

Windows 8

UI 线程处理

Windows 8允许的 VisualTreeHelper 函数调用,这些调用引用了错误 (而不是当前) UI 线程上的对象。 从 Windows 8.1 开始,如果未从当前 UI 线程调用该函数,则会引发异常。 考虑这种新行为应该是一个非常罕见的应用迁移方案;首先很难跨线程获取 UI 元素。

为 Windows 8 编译但在 Windows 8.1 上运行的应用使用Windows 8.1行为,并且将专门在 VisualTreeHelper 函数调用上引发,而不是针对使用跨线程对象的任何下游应用代码引发。

屏幕键盘的应用 UI

Windows 8有一个内部实现的逻辑,每当用户调用屏幕键盘时,该逻辑就会将 ScrollViewer 与整个应用 UI 相关联。 此屏幕键盘是用户通过“轻松使用中心”请求的特定辅助功能。 如果系统未检测到任何键盘设备,则它与可在应用 UI 中显示的文本输入控件的软键盘不同。 内部 ScrollViewer 在此处执行的操作是,如果由于键盘占用 UI 空间而强制滚动应用,则能够滚动应用所在的区域。

从 Windows 8.1 开始,出现屏幕键盘时,系统仍具有 UI/布局行为,但不再使用此内部创建的 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)

检索位于应用 UI 的指定 x-y 坐标点内的一组对象。 对象集表示共享该点的可视化树的组件。

FindElementsInHostCoordinates(Point, UIElement, Boolean)

检索位于应用 UI 的指定 x-y 坐标点内的一组对象。 对象集表示共享该点的可视化树的组件。

FindElementsInHostCoordinates(Rect, UIElement)

检索一组对象,这些对象位于应用 UI 的指定 Rect 框架中。 对象集表示共享矩形区域的可视化树的组件,并且可能包含过度绘制的元素。

FindElementsInHostCoordinates(Rect, UIElement, Boolean)

检索一组对象,这些对象位于应用 UI 的指定 Rect 框架中。 对象集表示共享矩形区域的可视化树的组件,并且可能包含过度绘制的元素。

GetChild(DependencyObject, Int32)

使用提供的索引,通过检查可视化树来获取所提供对象的特定子对象。

GetChildrenCount(DependencyObject)

返回可视化树中对象的子集合中存在的子级数。

GetOpenPopups(Window)

从目标 窗口检索所有打开的弹出控件的集合。

GetOpenPopupsForXamlRoot(XamlRoot)

从目标 XamlRoot 检索所有打开的弹出控件的集合。

GetParent(DependencyObject)

在可视化树中返回对象的父对象。

适用于

另请参阅