XAML如何在运行时解释和执行?

Wpf*_*bie 16 .net wpf xaml

在加载XAML(或BAML)和接收根对象(例如Window)之间内部会发生什么?

首先出现在我脑海中的是Reflecton用于创建对象,设置其属性等等.但也许我错了?

也许有人可以解释如何在运行时解析和执行XAML/BAML,或者给出一篇包含解释的好文章的链接?

为了使我的问题更清楚一点,让我们讨论一下这个简短的例子:

<Button Margin="10">OK</Button>
Run Code Online (Sandbox Code Playgroud)

因此,解析器看到需要创建一个Button对象,其Margin属性必须设置为10并且其内容必须设置为"OK".怎么做的?通过使用Reflection(加上TypeConverters等)?

Mik*_*bel 27

您可能会在.xaml.cs文件中注意到支持已编译的XAML文件的partial类被标记为类.XAML构建任务生成第二个.cs文件,其中另一个部分类部分包含该IComponentConnector.InitializeComponent()方法的实现,该代码的实现由后面的代码中的默认构造函数调用.这个方法基本上贯穿XAML(此时实际上是BAML形式)并使用它来"修复"新创建的对象,而不是从XAML源创建一个新对象,如果你将会发生这种情况.是用来XamlReader加载或解析一个对象.

因此,当您实例化一个新编译的XAML对象(例如,a UserControl)时,InitializeComponent()在构造函数中调用之前的任何代码都将执行.然后,在调用期间将处理在XAML文件中设置的所有属性和事件处理程序InitializeComponent(),之后构造函数将继续执行.这可能很有用,因为您可能希望确保在处理XAML文件之前或之后设置某些属性.

至于如何解析XAML,它基本上被读作表示属性赋值,对象声明等的XAML节点流,这些节点由服务中的顺序执行System.Xaml.该节点流基于公共对象模型,该公共对象模型可以是从BAML流,XML文档(例如,松散.xaml文件),另一个对象实例等构建的.BAML 比基于XML的格式更紧凑,解析通常更快.


附录:在您添加的示例中,您询问解析器如何看到Button需要创建对象和Margin集合.简短的回答是:这取决于.具体来说,它取决于用于读取XAML流的模式上下文.

XAML解析器使用自己的类型系统,其中至少有两个实现:

  1. 基于反射的标准CLR型系统System.ComponentModel;
  2. WPF类型系统,通过包含对依赖项属性和路由事件的特殊支持来扩展#1.

根据我对XAML语言规范的回忆,大致会发生什么:

  1. XAML解析器遇到StartObjectButton类型的节点(对于标准WPF命名空间映射)解析为该节点System.Windows.Controls.Button.这告诉解析器它需要创建一个Button对象的实例,它通过反射调用它的默认构造函数.
  2. 流中的下一个节点是一个StartMember节点,成员名称为Margin.WPF模式上下文的类型模型将此解析为Margin依赖项属性.
  3. Value接下来是一个节点,告诉解析器设置"10"(字符串)的值.解析器发现属性类型Thickness与字符串值不兼容.它查询其类型系统以查看[ValueSerializer]属性上是否存在Margin属性,该属性可用于转换字符串; 没有这样的属性.它检查属性的[TypeConverter]属性; 再一次,它找不到.它[TypeConverter]Thickness类型本身上查找属性并找到一个属性,指示它使用a ThicknessConverter将字符串值转换为a Thickness.它就是这样.由于Margin是依赖属性,它使用SetValue()API来设置属性值; 如果它是CLR属性,它将使用反射或a PropertyDescriptor.
  4. 一个EndMember节点告诉解析器结束属性赋值.
  5. 解析器遇到Value包含内容的节点"OK".解析器知道它正在构造一个复杂的对象,因此内容不能代表整个对象.它查找[ContentProperty]属性Button及其超类型; 它找到一个on ContentControl,表示该值应该用于设置Content属性(它被解析为相应的依赖属性). Content是一个object,所以它string直接赋值(再次使用SetValue()).
  6. 下一个节点EndObject告诉解析器它已经完成了Button对象的处理.

请注意,我使用术语"解析器"来简化操作.说实话,这一切都不会发生在解析阶段(如果"解析"阶段甚至存在).您可能认为"解析"阶段只是构建XAML节点流.声明对象的创建和/或填充实际上是通过将该流馈送到a XamlObjectWriter中来实现的,这简单地XamlWriter将XAML节点的实现写入对象(而不是XML文档或BAML流).在高层,只发生了两件事:

  1. XamlReader 将某些内容转换为XAML节点流.
  2. XamlWriter 将XAML节点流转换为某种形式.

在编译的XAML资源的情况下,编译时构建任务将a的输出管道XamlXmlReader化为BamlWriter"编译"XAML.在运行时,a的输入通过BamlReader管道输入XamlObjectWriter到创建或"修复"根对象.

一旦理解了所有这些,您就可以开始认识到XAML是一种强大的序列化和持久化格式,而不仅仅是构建UI的语言.