Xmal
xmal 中每个元素对应net中的一个类的实例。一般情况下,一个标签对应一个元素。
元素可以嵌套,表示类包含一个类
类有属性,所以元素也需要设置属性,这个通过特性来设置。如果特性不足以完成属性设置,需要通过特殊语法使用嵌套标签。
如上图
1.该xaml文档包括两个元素,因为只有Window 和Grid标签。其中Window的顶级元素,一个xaml只能有一个顶级元素。
顶级元素有Window,page,application
2.上述例子中,在Window的开始标签里有7个特性:分别是一个类,三个名称空间,还有三个属性。
其中三个Window属性,我们上面说了,元素的属性用特性来定义,所以这三个特性是表示Window的属性的。
另外三个名称空间,其中第一个是wpf核心名称空间,包含了所有Wpf类,包括用户界面的控件。这个名称空间
没有加前缀,所以是整个xaml文档的默认名称空间,除非另行指明,则每个元素自动位于这个名称空间下。
有一个前缀为x的名称空间,他是Xaml名称空间,他包含了各自Xaml的实用特性。
(是Xaml语言的相关特性,是语言层面上的特性,而第一个没有前缀的名称空间是表示wpf层面的,是两个不同层面的特性)
这就说明xaml元素对应net的类,xaml的特性要大于net类的属性。上面就是例子,只有三个特性是窗体类的属性,其他几个特性,要不是名称空间,要不是xml的解析规则。
若要使用Xaml的相关特性,需要在元素前面加x。
另外一个名称空间先不说。
还有一个特性是x:class这个表示该class是Xaml名称空间中的特性。这个class告诉Xaml解析器用指定的名称(就是class特性的内容,=后面的字符串)
创建一个类,该类继承自 由xml元素命名的类(也就是包含该特性的元素,本例中是window)。也就是说,创建了一个名叫window1的类,该类继承自window类。
也就是当XAML解析器将包含X:Class特性的Xaml解析成类以后,这个类叫什么,这个类继承自拥有这个标签的元素所对应的类。
所以window1类时编译时自动生成的,但是只有界面没有逻辑的话,窗口是没有用的,所以我们需要提供部分类,包括事件处理那部分的内容。
这个正式C#语言的的partial class特征实现的。在编译过的程序集中吧这些独立的部分融合到一起。
vs会自动为我们创建这部分类。
window1的隐藏代码类中包含一个无参构造函数,该函数调用了InitializeComponent方法,这个方法非常重要,必须有。
这个方法调用了LoadComponent方法,从程序集中提取BAML(编译过的XAML),并用他来构建用户界面,
解析BAML时,创建每个空间对象,设置其属性,并关联所有事件处理程序
命名元素
命名元素有两种方法。
一种使用XAML的Name特性 即x:Name=“”
一种是不用XAML特性,直接写Name=“”
这两种方法不同,但是结果相同。
第一种是XAML语言的一部分。和wpf类无关。第二种是WPF类中使用了RuntimeNameProperty特性修饰之后,可以使用Name特性
而FrameworkElement类使用了这个特性,并且所有WPF的类都继承自这个类。所以可以使用Name特性。
两个的区别在这里:一个是XAML语言的特性,即XAML语言部分。一个是WPF类的特性,即WPF部分。
XAML中的属性和事件
Xam中元素的属性是通过特性来设置的
1.为对象属性赋值
分为两种情况:
1)使用字符串进行简单赋值。这种情况类的属性与xaml的特性可以一一对应,只需要为类的属性做好正确的类型转换。因为xaml的特性是有字符串,而类的属性有很多类型。
2)使用属性元素进行复杂赋值。因为特性的值是一个字符串,复杂程度有限,而类的属性的复杂程度可以是好几层的其他类,如果采用特殊格式的字符串为之赋值,就太头疼了。
为了解决第一种赋值的问题,可以看下面的列子
缺少TypeConverter,引发了错误,所以需要手动写一个
写完再类上面加上特性
成功给属性赋值。
通过上面例子,我们知道,wpf的特性给属性赋值,在内部写好了转换器,当赋值时,先查找属性有没有
Typeconvert特性,如果没有再查找属性的数据类型的那个类有没有Typeconvert特性,在这个例子中就是
staff对象的person属性,因为person属性本身没有类型转换特性,所以查找到person属性的类型,person类
具有特性。所以转换成功。
第二种情况是,有的类的属性是另外一个对象,而这个对象又有自己的属性。这样如果也用上面的方法,也
可以,就是需要创建一定格式的字符串,以供类型转换器来转换成对应的类的对象。但是这种方法很复杂,编程
复杂,而且对于格式的要求过于繁杂,容易出错。所以采用了元素属性。
顾名思义,属性是一个元素,这个元素是包含在父标签的内容中的。所以他是父元素的子元素。而他又是父元素
的属性,所以叫做元素属性。
上面两种为属性赋值的方式都是新生成一个对象,也就是写死了属性值。而在实际应用中,有可能需要用已有的对象,
赋值给多个属性,也有可能将摸个元素的属性赋值给另外一个元素的属性。也有可能将属性赋值为null。这就是上面两种
方式无法实现的。
因此有了扩展标记
如图,扩展标记用花括号表示,扩展标记也是一个对象,他的类型是左边花括号紧邻的类型,上图的例子就是xaml名称空间中的static类型。
类实例化为对象时,会将类型右边的字符串传入构造函数,给对象属性赋值。
也就是
当编译器看到花括号时
1.会将花括号实例化为一个对象
2.对象的类型时左花括号紧邻的字符串
3.对象的属性由含有逗号的一串字符串负责初始化。
可见标记扩展使用非常方便,但是并不是所有对象都可以使用标记扩展。
标记扩展类继承自 System.Windows.Markup.MarkupExtension。这个类提供了一个
ProvideValue,这个方法返回所需要的的类型。
具体过程是,当编译器遇到上面的x:static时,会创建ataticExtension类,会调用构造函数,并且将字符串传入构造函数中,然后检查标记扩展的等号左边
的属性Foreground的类型,然后发现是Brush,最后调用ProvideValue方法,返回Brush对象,并赋值给Foreground。