标题:详解Silverlight的对象树
作者:网友
日期:2023-05-02 21:45:57
内容:

在托管代码或 JavaScript 中,您可以在运行时期间引用 Silverlight 的 Silverlight 对象树中的 对象。本主题介绍如何在 Silverlight 托管 API 中使用对象树。

对象树

对象树概念描述如何使在运行时在 Silverlight 内容中创建和存在的对象彼此相关。关系基于对象具 有属性这一原则,在很多情况下属性的值是另一个对象,而此对象也具有属性。对象树具有分支,因为其 中某些属性是集合属性并具有多个对象;并且,对象树具有根,因为体系结构最终必须引用单个对象,而 该对象是与对象树之外的概念(例如,浏览器宿主或显示内容的 Silverlight 插件)之间的连接点。

尽管在概念上实际只有一个对象树,但 Silverlight API 不向您公开完整的树。大量的对象树结构实 际上是实现详细信息。而您具有对象特定的属性,这些属性影响树中特定点的子项值并且可能报告父项( 在大多数情况下,父轴是只读的,因为您通常是在代码中或通过 XAML 分析过程从根向上构建树)。例如 ,Panel 具有其 Children 属性,该属性设置子对象。FrameworkElement 具有用于报告父项的 Parent。 这两个 API 都在基类中,因此,它们可用于大量的 Silverlight 对象。

Silverlight 中一个相关的树概念是可视化树。可视化树概念指的是较大的对象树在经过编辑或筛选 后的表示形式。所应用的筛选器是在可视化树中只存在具有呈现含义的对象。例如,某个集合类不是可视 化树的一部分,而可视化树将集合抽象为一个“子项”概念。然而,如果您将加载的源 XAML 标记视为与 对象树近似的结构,则可视化树也可以包含并不直接显示的对象。这是因为,可视化树也报告作为特定控 件(这些控件来自所应用的控件模板或资源字典)的组成部分的对象。可视化树在内部用于 Silverlight 呈现过程,但了解一些有关可视化树的内容对于某些情形通常很重要,例如,在应用模板后编写或替换控 件模板或在运行时分析控件实例。对于这些情形,Silverlight 提供了 VisualTreeHelper API,它通过 一种方式检查可视化树,这种方式比您通过对象特定的父属性和子属性来实际实现更为一般化。

可视化树概念也存在于 WPF 中,它与 Silverlight 的可视化树概念类似。然而,一个显著的差异是 WPF 还提供一个附加的筛选器或对象树(称为“逻辑树”)的概念。逻辑树概念与某些属性系统行为相关 。Silverlight 不通过帮助器类来公开此逻辑树。Silverlight 中的确存在某些(但并非所有)相关的属 性行为,但由于没有用于访问这些行为的帮助器 API,因此,逻辑树概念在 Silverlight 中将没有用武 之地,因此本文档不讨论它。缺少逻辑树而引发的一个很小的兼容性问题是:FrameworkElement.Parent 属性行为在 Silverlight 版本 3 中是不同的,它实际上报告可视化树父项。

对象树和 XAML 标记

如果您将通过 Silverlight API 访问的对象树与 XAML 标记的树形状进行比较,它们在节点方面并不 完全匹配。这是因为 XAML 用于标记,并且在标记定义期间易于使用。例如,XAML 具有属性元素的概念 ,它提供相关的指导信息,当您发现一个元素嵌套在另一个元素内时,您可以选择要设置的属性。在对象 树中,这就像一个对象上的某个属性由另一个对象进行设置一样。相反,XAML 也具有内容属性的概念, 其中,所设置的属性在标记中甚至没有显式进行命名。XAML 具有的语法可以基于属性的字符串值创建对 象,也可以针对 XAML 标记中已存在但在其他位置定义的对象提供引用,或者完全位于标记外部。尽管存 在这些很小的不一致,但当您在 XAML 中定义用户界面时,您将在运行时定义最终 Silverlight 对象树 的近似结构。

引用对象属性

无论您通过何种方式从 Silverlight 对象树中获取对象引用,都将通过 object.property 表示法( 与 .NET 中 CLR 属性的核心概念相关)直接公开托管 API 中的属性。许多 Silverlight 2 属性的基础 是依赖项属性概念。依赖项属性和属性系统引入了一些其他可能的语法,用于通过与 object.property 不同的方式访问属性,但与附加属性的情况不同,这些属性并不常用,因此本主题不讨论它们。主题依赖 项属性概述中详细讨论了依赖项属性。

对象树中的附加属性

Silverlight 支持附加属性的概念。从对象树的角度来看,附加属性是可以附加到树中任何对象的属 性,而不考虑该对象的类型(尽管在 Silverlight 实现中,该对象至少必须是依赖项对象)。附加属性 值存在于对象树中,但是,如果您使用代码来访问它们,则必须使用与 object.property 表示法不同的 语法。

对象树中的资源和模板

Silverlight 支持一个称为资源字典的资源概念。资源字典用于指定自身需要大量子属性设置的属性值。

ResourceDictionary 最常见的方案是在 XAML 中定义 ResourceDictionary 元素,然后通过 XAML 属 性 (attribute) 和 StaticResource 标记扩展将已定义的资源用作属性 (property) 值。对于某些情况 ,可以共享此资源。例如,您可以定义一个 LinearGradientBrush(它在 ResourceDictionary 中包含多 个渐变停止点),然后将其应用于可视化设计中的多个 Brush 属性(可能在位于不同页的用户界面中) 。

模板将按稍微不同的概念运行(无论是在页级别还是在应用程序级别资源字典中定义,也无论是在 generic.xaml 中还是以内联方式)。模板自身是一个对象,但模板可能多次应用于可视化树。在应用后 ,模板中的元素通常使用 TemplateBinding,这样,就可以应用模板并仍然设置由模板化对象保留的特定 值。有关模板的基础概念将在主题通过使用 ControlTemplate 自定义现有控件的外观中讨论。

遍历对象树

遍历对象树在对象模型中是一种通用的方法。遍历树意味着您可以使用针对包含对象引用子对象(通 常,这些是集合)或父关系的属性(这通常是在集合内完成的,并返回集合自身)。我们可以对此过程进 行粗略的说明:您调用一连串子属性和父属性(或可能调用帮助器方法)以导航对象树的各个轴,直到您 检索到包含您所查找的对象的值。

通常,您应该可以在 XAML 中针对 Silverlight 构造您的内容,这样,您就不需要大量查询树的结构 。为了避免需要遍历树,请在创建元素的 XAML 中对于 x:Name / Name 属性向这些元素提供一个值。这 就创建了一个直接引用,该引用可用于标记从 XAML 编译的类中,与遍历树相比,这种获取对象的方法出 错的可能性要低得多。

此外,如果您通过代码构造函数而不通过 XAML 加载来创建对象,则您应该能够构造您的代码,以便 您可以定义私有字段或变量来在运行时保留对象引用(保留在类中,或在应用程序级别存储为变量)。

然而,在某些情况下,向对象提供名称并在范围中保留对象引用是不可能的,也是不切实际的。一个 此类方案是:您正在添加由用户提供或通过数据绑定提供的动态内容,而您无法预测所添加的项数或运行 时对象树的结构。另一个方案是检查对于某个控件所应用的模板,或控件的某个组成部分。

警告说明警告:

Silverlight 通常支持“设置外观”概念,也称为重新设置控件样式或控件重新模板化。尤其是,如 果您是控件作者且正在编写控件的支持代码,则假定特定的树结构可能很危险。因为大多数控件支持可设 置的模板(无论您是否已启用多个特定的扩展点,如子部分样式),所以,运行时可视化树可能与通过所 应用的默认模板创建的树不同。请参见通过使用 ControlTemplate 自定义现有控件的外观。

用于遍历“子项”和其他集合的 Try-catch 逻辑

如果您遍历对象树的要求涉及到查找某些对象,而这些对象所表示的集合未表示为可视化树的一部分 ,则您可能需要编写专用的函数,以便尝试查找与特定的命名模式或特定类的对象模型相匹配的 API。

向下(远离根)遍历对象树的多个级别通常是可能的,只要您了解所包含的对象将具有集合的点。您 可能必须使用 try/catch 方法或其他等效方法来检测这一点,即检查 Children 是否存在以及 Count 是 否为非零值(此处的 Children 和 Count 是占位符,而不是文字 API;根据 .NET 命名原则,Children 和 Count 刚好是这些类型的属性的公共名称,但根据对象及其对象模型,实际属性可能具有不同的名称 )。总体 Silverlight 对象模型中的某些集合包含在未命名为 Children 的属性中。如果您知道您正在 遍历到某个未命名为 Children 的特定集合属性,则应在逻辑中说明此情况。

使用 VisualTreeHelper

VisualTreeHelper 是一个可用于遍历对象树的实用工具类。(可视化树的概念已在本主题前面的“对 象树”一节中介绍。)

因为您可以在运行时对可视化树执行操作,并且可以遍历到模板部件,所以这可能是一种可用来检查 模板组成情况的有用手段。此外,您可以检查可能通过数据绑定填充的子集合,或者您的应用程序代码可 能无法全部了解运行时对象树的完整本质的子集合。为此,您可以通过 GetChild 并将 GetChildrenCount 用作一个确定因素(确定树节点是单个项还是应按计数进行迭代的“子项”集合)来 遍历该树。

遍历模板内容

除VisualTreeHelper 之外,可用来遍历模板内容的另一个方法是 GetTemplateChild。使用 GetTemplateChild 或遍历模板内容通常是必要的,因为 FindName 的行为由名称范围概念控制。在这种 情况下,模板内容与对象树的其他部分具有特意不同的名称范围,因为模板是共享的,如果不采用单独的 名称范围,则在多次应用模板时会导致名称冲突。GetTemplateChild 按其模板名称范围 x:Name 值查找 对象,同时从应用该模板的特定 Control 的更大对象树范围中遍历。

Silverlight 对象和 HTML DOM

还有另一个对象模型可用于为 HTML 编写脚本:HTML 文档对象模型 (DOM)。然而,DOM 不会将 Silverlight 插件加载的内容标识为 DOM 的一个完整部分。


返回列表 网站首页