XAML 分析器体系结构
适用于 Visual Studio 的 WPF 设计器加载可扩展应用程序标记语言 (XAML) 文档并创建要在 Visual Studio 中显示的 WPF 对象。 在加载的过程中遇到的错误将显示在“错误列表”窗口中。
XAML 加载阶段
WPF 设计器加载一个 XAML 文档,并创建相应的“抽象语法树 (AST)”。 AST 是表示分析的 XAML 的数据结构。 它是带有标签的有限定向树,其中的内部节点由运算符标记,叶节点表示节点运算符的操作数。 叶具有空运算符,这些运算符是变量或常量。
加载 XAML 文档的过程在一系列阶段中发生,如下表所示。
XAML 加载阶段 |
说明 |
---|---|
XML 语法验证 |
扫描仪:执行词法处理过程,包括检查任何格式错误,检查无效字符并创建词法标记。 分析器:创建 AST 并执行对分析,以确保标记格式正确且平衡。 |
XAML 语法验证 |
ConvertToXaml 查找所有类型,将类型信息置于 XAML AST 中,并对 XAML AST 添加批注。 验证将执行错误检查,并检查节点在树中的位置。 |
模型和对象实例化 |
具有单独演练 AST 的离散阶段,将创建编辑模型和 WPF 对象。 |
在以前的阶段中出现错误的节点被标记为错误节点,将不再在任何后续阶段中访问。 如果在扫描仪和分析器阶段中遇到错误,将不尝试模型和对象实例化阶段。
XML 语法验证
扫描仪和分析器阶段验证要加载的文档是否是不包含 XML 语法错误的格式良好的 XML 文档。 XML 语法错误的一个示例是 <Button> 标记没有匹配的 </Button> 结束标记。 分析器尝试进行错误恢复,因此在分析文档时可能会从一次尝试中报告多个错误。
XAML 语法验证
分析器在不同的处理过程中遍历 XML AST,以验证文档是否是有效的 XAML 文档,有效意味着文档符合 XAML XML 架构,并且不包含无效的 XAML。 无效 XAML 的一个示例是使用无效属性声明的元素,例如 <Button SomeProperty="Mark">。
这些处理过程包括类型解析,因此可针对元素类型对元素名称和属性名称等信息进行验证。 例如,分析器检查 SomeProperty 是否是 Button 上的属性。 缺少类型会引起错误。
分析器尝试进行错误恢复,在分析文档时可能会从一次尝试中报告多个错误。 但是,并不会对所有可能的错误都进行报告。 例如,如果一个元素名称拼写错误,该元素中的属性名称也拼写错误,那么最初将只报告元素错误,因为在正确解析元素之前,还不能验证属性名称。
提示
此阶段不包括属性值的验证。 例如,此阶段中不检测 <Button Background="xBlue"/>。 请参见本主题后面的论述。
模型和对象实例化
在语法验证结束时,有一个与 XAML 对应的 AST,特定于 XAML 的文档树用作该 AST 中的视图或光标。
在最后一个阶段中,将对模型和基础实例进行实例化,并将指定从字符串转换的属性值。 分析器通过使用文档树管理器类创建文档树来执行此操作。 为 XAML 创建文档树时,将同时创建基础 WPF 实例。 这些实例在设计器中用作视图。
如果在创建模型和实例时引发异常,在出现错误的节点处将无法完成为其子节点创建任何对象的操作。 将为树的其余部分构造模型。 这样会暴露出尽可能多的错误。
例如,在代码段 <Button Background="Test"/> 中,用于 Brush 类型的 TypeConverter 尝试将 Test 转换为 Brush 实例。 由于 Test 不是有效的 Brush 值,因此类型转换器引发的异常将停止用于任意子节点的分析过程,但异常不会影响文档其余部分的分析。
对所属对象进行实例化时,将从字符串转换属性值。 在设计图面上使用所属对象时,将发生这种情况。 在设计器使用父对象之前,许多值范围错误都不会报告。
此行为类似于 WPF 编译。 WPF 编译器在编译期间不验证或尝试转换特性(属性)值。 在 WPF 在运行时实例化对象树之前,不会调用类型转换器。
提示
在加载外部资源字典时,编辑模型和分析器之间存在交互。 当编辑模型必须加载其他 XAML 文件时,将会触发 XAML 加载操作。
错误消息
WPF 设计器错误消息的帮助主题描述哪个 XAML 加载阶段引发了错误。 下表显示了消息与阶段的对应关系。
XAML 加载阶段 |
错误消息 |
---|---|
XML 语法验证 |
当 XAML 文件不是格式良好的 XML 文档时,便会引发此错误。 |
XAML 语法验证 |
当文件是一个有效的 XML 文档但不是格式良好的 XAML 文档时,便会引发此错误。 |
模型和对象实例化 |
当文件是一个格式良好的 XAML 文档但包含一个或多个类型不匹配时,便会引发此错误。 |