卷首语:根据第一篇的知识,我们知道WPF应用是由控制台程序创建的,拥有自己独立的消息循环。所以在之后的文章里和示例里,我会默认的选择开启控制台显示,以方便调试以及输出一些信息。并且为了简便,推荐直接创建WPF项目,因为毕竟没有人真会无聊到拿控制台去管理一个WPF应用的生命周期,也没人会New一个又一个的Window对象和Controls。因为WPF有自己的UI展现形式——XAML。
言归正传:
我们先来弄明白XAML的定义
XAML是一种相对简单的、通用的声明式语言,它适合于创建和初始化.NET对象,XAML本身并不具备有意义的元素,它仅仅是提供一些关键字及规则,来告知编译器和解析器如何处理XML。
从它的定义中,我们可以看到XAML是一种声明式语言,拥有通用性。并且它的作用受到了限制,仅仅适合用于创建和初始化.Net对象。这两个特性告诉我们什么呢?就是XAML语言可以被应用在.NET平台下的其它语言或者其它技术中,如WF。
那么XAML与WPF是什么关系呢?
XAML是通用的 那么它就不应该受到框架的限制,因此它与WPF是相互独立的,比如可以使用单独的XAML语言来创建窗体、控件等。然而XAML并不是万能的,就如同XML一样,也同样需要解析。我们在实现一个WPF应用时,可以选择是否使用XAML,因为XAML的作用是创建和初始化.NET对象,每一件XAML可以做到的事情,任何一门.NET语言都可以做到,然而反过来则不行。举个不恰当的例子……巴基斯坦和卡巴斯基有神马关系?回答:基巴关系。 嗯是的,确实只有基巴关系,卡巴斯基是通用的,但是也得有人用,巴基斯坦人民可以选择是否使用卡巴斯基来简化杀毒这件事情的工作……
以上说了一堆废话,也比较难以理解,还请大家见谅,因为看WPF揭秘的时候这里就很难理解。反复看了很多遍,一直很纠结,挠墙的心都有了。其实这里只是想大家能有一个基本的认识,XAML != WPF。XAML虽然是针对WPF设计的,但XAML的应用并不限制于WPF,只要有合适的解析方式,XAML可以适用于任何语言和技术的展现。另外补一句……打算看书自学的……先看WPF设计指南吧……揭秘这本书……太高深了……
下面我们来看一段简单的XAML,也是WPF模版生成的Window窗体的XAML
<Window x:Class="WPF_Xaml_Study.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> </Grid> </Window>
这段Xaml 如果了解XML的朋友看起来并不困难,从XML的视角来看它拥有
一个Window 类型的根元素和一个Grid类型的子元素
Window根元素命名空间为 http://schemas.microsoft.com/winfx/2006/xaml/presentation
自定义x命名空间http://schemas.microsoft.com/winfx/2006/xaml
Title Height Width 是Window元素的 Attribute 称为特性
以XML的世界观看完了这段XAML,我们再来以XAML的世界观来看
x:Class 的作用是为根元素定义一个派生自元素类型的类 也就是标记了这个Window实例化的不是原始的Window 而是WPF_Xaml_Study.MainWindow
Window的命名空间包括了System.Windows命名空间下的绝大部分命名空间及类型。
x命名空间包括了扩展标记类型
Title Height Width 对应了Window类型的对应属性 因此也称为 Property Attribute 属性特性
下面我以一个简单的Button控件的例子 来一一对应XAML与CLR中相应类型的关系
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK"></Button>
Button 实际是由System.Windows.Controls提供的 它在CLR中对应的状态应该是怎样的呢?
//等同于Xaml中声明的Button Button button = new Button();
button.Content = "OK";
它声明了一个Button对象,并且将其Content属性设置为了 "OK"
XAML中,元素 Attribute的定义有两种 一种是对应的CLR中的类型属性,另一种 是对应的CLR中的类型的事件
其实XAML应用起来 还是比较简单的
下面我们来看XAML的神奇亮点之一 ( 命名空间 )
在XML中,也有命名空间的概念,XML的命名空间往往就是一段唯一的URL 如:http://schemas.Microsoft.com
而在XAML中,命名空间有两种声明方式。
第一种很传统,还是用的URL方式
http://schemas.microsoft.com/winfx/2006/xaml/presentation
第二种更传统,使用的是CLR 程序集、命名空间的方式
xmlns="clr-namespace:System.Windows;assembly=PresentationCore"
xmlns="clr-namespace:System.Windows;assembly=PresentationFramework"
在刚刚的Button例子中 这两种方式的效果是等价的。
这是为什么呢?
答案很简单 http://schemas.microsoft.com/winfx/2006/xaml/presentation这个看似简单的命名空间,包含了N多的System.Windows下的各个子命名空间的中的类型。比如Button就被定义在PresentationFramework这个程序集的Controls命名空间下
下图罗列了这个命名空间所包含的CLR命名空间
这么一个XML命名空间引入了这么多的CLR命名空间很神奇是不是?这要用using 不定要引入到猴年马月呢。
其实这个命名空间,是通过在程序集中进行了硬编码,将CLR的命名空间映射为了XML的命名空间。
我们可以设置自己的XML命名空间与CLR命名空间的映射。
在AssemblyInfo中 ,使用XmlnsDefinitionAttribute 添加CLR命名空间对应XML命名空间的映射
XmlnsDefinitionAttribute 位于System.Windows.Markup命名空间下
[assembly: XmlnsDefinition("http://Manon.Loki.Com","WPF_Xaml_Study")]
由于XML命名空间与CLR命名空间是1对多的的关系,所以要注意其中的类型是否存在二义性
XAML 亮点之二 (属性元素)
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK"></Button> <Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" > <Button.Content> OK </Button.Content> </Button>
通过对比两个Button, 我们可以发现设置Button的Content拥有两种方式。
第一种 通过Attribute进行设置
第二种 通过子元素进行设置,时候Content元素就被称为属性元素,而Button则为对象元素,中间使用.进行分隔符
<ObjectElement.PropertyElement> 这种通用的写法。
WPF提供了属性元素有什么好处呢?
一个类型的属性不一定是简单类型,如果是复杂类型的话, Attribute就无法进行正确的表达,这时候可以以属性元素的方式,进行精确的表达。
例如:我想让Button的Content是一个图形,而非普通的文字,只需要在Content属性下创建符合该类型值的子类就好。
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <Button.Content> <Rectangle Width="50" Height="50" Fill="Red"></Rectangle> <Button.Content> </Button>
XAML亮点之三 (扩展标记)
这个要说的不多,大家知道其大概意思及原理即可。
WPF提供了几个扩展标记 位于System.Windows.Markup命名空间下
其对应的XML命名空间http://schemas.microsoft.com/winfx/2006/xaml
系统提供了很多扩展标记 如:Static Null Binding等。
那么扩展标记是如何工作的呢?
下边写一个简单的例子
<Button Content="使用扩展标记设置Background" Background="{x:Null}" Height="{x:Static Member=SystemParameters.IconHeight}"></Button>
Background与Height都使用了扩展标记。
其中Height的 x:Static Background的x:null为标记扩展类型。
Member为命名参数
最后的字符串SystemParameters.IconHeight 被称为定位参数
我们要注意扩展标记仅适用于 Attribute 在使用的时候 通过"{}" 括起来 表示这是一个扩展标记而非一个普通的字符串。
"{}"中的字符串会根据标记扩展类型去查找对应的处理类,并且根据定位参数来获取值
由于存在标记扩展的因素,所以我们在赋予XAML 带有{}的字符串类型的值得时候,要避免被系统认为是标记扩展
以下为两种解决方式
<!--方式1 使用一个{}表示扩展标记,而后跟随声明的值--> <Button Content="{}{这是一个带花括号的Button}"></Button> <!--方式2 使用属性元素,因为只有在Attribute中 花括号才会被认为是扩展标记--> <Button> <Button.Content> {同样是一个带花括号的Button} </Button.Content> </Button>
XAML亮点之四 (内容属性)
内容属性其实很简单,就是每个控件都有一个默认的属性,当对这个控件类型的内容赋值时,会自动把值赋给指定的属性。
例如Button的Content就是它的内容属性。因此通过XAML对Button的Content赋值的时候可以有一种简写的写法。
<Button>It's a Button</Button>
其它的的控件 例如ListBox的Items为内容属性。一个控件内容属性的确定大体上是根据控件的类型来决定的
以上为XAML与XML不同的地方。
下面是额外的一些知识 了解即可,因为这是编译器帮我们做的。
我们在项目中创建了MainWindow.xaml与MainWindow.xaml.cs
当我们编译整个项目的时候
MainWindow.xaml会被编译为MainWindow.Baml
MainWindow.xaml.cs会被编译喂MainWindow.g.cs
BAML(Binary Application MarkUp Language)的缩写,这是一种被解析之后生成的二进制文件,它会作为默认的二进制资源嵌入到程序集中。因此不用纠结大批量的XAML文档处理问题。
MainWindow.g.cs为系统生成的类型 会被编入程序集 对应MainWindow.xaml.cs
Tips:这一篇就这么多了。看书啃得很累,写出来也发现很累,希望大家以辨证的眼光来看待这篇文章,因为那本WPF揭秘实在是太深奥了。还是那句老话,也许我理解会有偏差 希望大家看到了 能及时提醒我 谢谢