默认 XAML 架构上下文和 WPF XAML 架构上下文

XAML 架构上下文是一个概念实体,它限定使用特定 XAML 词汇的 XAML 生产环境如何与对象写入行为交互,包括类型映射的解析方式、程序集的加载方式、某些读取器和写入器设置的解释方式。 本主题介绍 .NET XAML 服务的功能和关联的默认 XAML 架构上下文(基于 CLR 类型系统)。 本主题还介绍了用于 WPF 的 XAML 架构上下文。

默认 XAML 架构上下文

.NET XAML 服务实现并使用默认 XAML 架构上下文。 默认 XAML 架构上下文行为在 XamlSchemaContext 类的 API 中并不总是完全可见。 但是,在许多情况下,默认 XAML 架构上下文影响的行为可以通过以下 API 观察到:XAML 类型系统的公共 API(例如 XamlMemberXamlType 的成员),或使用默认 XAML 架构上下文的 XAML 读取器和 XAML 写入器上公开的 API。

你可以通过调用 XamlSchemaContext 构造函数来创建封装默认行为的 XamlSchemaContext。 这会显式创建默认 XAML 架构上下文。 如果使用未显式采用 XamlSchemaContext 输入参数的 API 初始化 XAML 读取器或 XAML 写入器,则会隐式创建相同的默认 XAML 架构上下文。

默认 XAML 架构上下文依赖于 CLR 反射来实现其类型映射行为。 这包括检查定义 CLR Type 和相关的 PropertyInfoMethodInfo。 此外,使用类型或成员的 CLR 属性来填写 XAML 类型的详细信息或使用 CLR 后备类型的 XAML 成员信息。 默认 XAML 架构上下文不需要类型系统扩展技术,例如 Invoker 模式,因为 CLR 类型系统中提供了必要的信息。

对于程序集加载逻辑,默认 XAML 架构上下文主要依赖于 XAML 命名空间映射中提供的任何程序集值。 此外,LocalAssembly 可以提示要加载的程序集,用于加载内部类型等场景。

WPF XAML 架构上下文

本主题介绍 WPF XAML 架构上下文,因为 WPF 实现提供了一个有趣的的示例,阐释了可以通过实现非默认 XAML 架构上下文引入的功能类型。 另外,在涉及 WPF XAML 的 WPF 文档中,对 XAML 架构上下文概念的讨论不多;只有结合针对默认 XAML 架构上下文工作原理的讨论,才能完全理解 XAML 架构上下文实现的行为。 WPF XAML 架构上下文实现以下行为。

查找替代:WPF 有几个 XAML 内容模型,其中有一些 XAML 内容属性在没有被 ContentPropertyAttribute 特性化的情况下运行。 WPF 的 LookupContentProperty 替代实现了此行为。

WPF 表达式的延迟:WPF 具有多个表达式类,它们将值延迟到运行时上下文可用为止。 此外,模板扩展是一种依赖于延迟技术的运行时行为。

类型系统查找优化:WPF 具有广泛的 XAML 词汇和对象模型,包括继承到数百个 WPF 定义类的基类成员定义。 此外,WPF 本身分布在多个程序集中。 WPF 使用查找表和其他技术优化其类型查找。 相比默认 XAML 架构上下文及其基于 CLR 的类型查找,这样做可以提高性能。 在查找表中不存在类型的情况下,该行为使用类似于默认 XAML 架构上下文的 XAML 架构上下文技术。

XamlType 和 XamlMember 扩展:WPF 使用依赖属性扩展属性概念,并使用路由事件扩展事件概念。 为了使这些概念在 XAML 处理操作中具有更大的可见性,WPF 扩展了 XamlTypeXamlMember,并添加了报告依赖属性和路由事件特征的内部属性。

访问 WPF XAML 架构上下文

如果使用基于 WPF System.Windows.Markup.XamlReaderSystem.Windows.Markup.XamlWriter 的 XAML 技术,则 WPF XAML 架构上下文已在这些 XAML 读取器和 XAML 写入器实现上使用。

如果使用未通过 WPF XAML 架构上下文初始化的其他 XAML 读取器或 XAML 写入器实现,可能能够从 XamlReader.GetWpfSchemaContext 获取有效的 WPF XAML 架构上下文。 然后,可以将此值用作其他使用 XamlSchemaContext 的 API 的初始化。 例如,可以调用 XamlXmlReader 进行初始化并传递 WPF XAML 架构上下文。 或者,可以将 WPF XAML 架构上下文用于 XAML 类型系统操作。 这可能包括 XamlTypeXamlMember 的构造初始化,或调用 XamlSchemaContext.GetXamlType

请注意,如果从纯 XAML 节点流的角度访问 WPF XAML 的某些方面,则某些 WPF 框架功能可能尚未起作用。 例如,尚未应用控件的 WPF 模板。 因此,如果访问在运行时可能填充有完整可视化树的属性,可能只会看到引用模板的属性值。 如果在非运行时情况下提供,为 WPF 标记扩展提供的服务上下文也可能不准确,并且在尝试写入对象图时可能导致异常。

XAML 和程序集加载

XAML 和 .NET XAML 服务的程序集加载与 CLR 定义的 AppDomain 概念集成。 XAML 架构上下文根据 AppDomain 的使用和其他因素,解释如何在运行时或设计时加载程序集或查找类型。 逻辑略有不同,具体取决于 XAML 是用于 XAML 读取器的宽松 XAML、由 XamlBuildTask 编译成 DLL 的 XAML,还是由 WPF 的 PresentationBuildTask 生成的 BAML。

WPF 的 XAML 架构上下文与 WPF 应用程序模型集成,后者又使用 AppDomain 以及其他属于 WPF 实现细节的因素。

XAML 读取器输入(宽松 XAML)

  1. XAML 架构上下文循环访问应用程序的 AppDomain,从最近加载的程序集开始,查找匹配名称所有方面的已加载程序集。 如果找到匹配项,则使用该程序集进行解析。

  2. 否则,使用基于 CLR Assembly API 的以下技术之一来加载程序集:

XamlBuildTask

XamlBuildTask 用于 Windows Communication Foundation (WCF) 和 Windows Workflow Foundation。

请注意,通过 XamlBuildTask 的程序集引用始终是完全限定的。

  1. 对限定名称调用 Assembly.Load(String)

  2. 如果上一步失败,则使用短名称和公钥令牌(如有)来调用 Assembly.Load(String)

BAML (PresentationBuildTask)

BAML 的程序集加载有两个方面:加载包含 BAML 作为组件的初始程序集,以及为 BAML 生产环境引用的任何类型加载类型支持程序集。

初始标记的程序集加载:

对要从中加载标记的程序集的引用始终未限定。

  1. WPF XAML 架构上下文循环访问 WPF 应用程序的 AppDomain,从最近加载的程序集开始,查找匹配名称所有方面的已加载程序集。 如果找到匹配项,则使用该程序集进行解析。

  2. 如果上一步失败,则使用短名称和公钥令牌(如有)来调用 Assembly.Load(String)

BAML 类型的程序集引用:

BAML 生产环境中使用的类型的程序集引用作为生成任务的输出,始终是完全限定的。

  1. WPF XAML 架构上下文循环访问 WPF 应用程序的 AppDomain,从最近加载的程序集开始,查找匹配名称所有方面的已加载程序集。 如果找到匹配项,则使用该程序集进行解析。

  2. 否则,将使用以下技术之一来加载程序集:

    • 对限定名称调用 Assembly.Load(String)

    • 如果短名称 + 公钥令牌组合与从中加载 BAML 的程序集匹配,则使用该程序集。

    • 使用短名称 + 公钥令牌调用 Assembly.Load(String)

另请参阅