零起点学习WPF之《WPF揭秘》读书笔记(1)
一、XAML的定义
XAML是一种相对简单、通用的声明式编程语言,它适合与构建和初始化.NET对象。
XAML 仅仅是一种使用.NETAPI的方法。
二、元素和特性
XAML规范定义了一些规则,用于把.NET命名空间、类型、属性和事件映射为XML命名空间、元素和特性。
XAML 与 C#对比
XAML
<Button xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content = "OK"/>
C#
System.Windows.Controls.Button b = new System.Windows.Controls.Button();
b.Content = "OK";
虽然两段代码是相同的,但你可以很快地在IE浏览中查看XAML,还会看到一个活生生的按钮放在浏览器窗口中。而C#代码则必须要用额外的代码编辑器编译后方可使用。
在XAML中定义个XML元素(叫对象元素)与.NET中实例化一个对应的对象(总是使用默认的构造函数)是等价的。
设置对象元素的一个特性(attribute),与设置一个同名属性(property attribute,称为属性特性)或者为一个同名事件设置一个时间处理函数处理程序(也称为事件特性),也是等价的。
XAML
<Button xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content = "OK" Clikc = "button_Click"/>
C#
System.Windows.Controls.Button b = new System.Windows.Controls.Button();
b.Click += new System.Windows.RoutedEventHandler(button_Click);
b.Content = "OK";
注意:XAML和C#一样都区分大小写。但是XAML的类型转换器中不区分大小写。
三、命名空间
XAML文件的根对象元素必须指定至少一个XML命名空间,用于验证自己和子元素。你可以(在根元素或者子元素上)声明额外的XML命名空间,但每一个命名空间下的标识符都必须有一个惟一前缀,
例如:WPF的XAML文件都会使用第二个命名空间加上前缀X(记作xmlns:x而不仅仅是xmlns)
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" , 这是XAML语言命名空间,用于映射System.Windows.Markup命名空间中的类型,而且它也定义了XAML编译器或解析器中的一些特殊的指令。
WPF把下面的所有.NET命名空间映射到XML命名空间
http://schemas.mircosoft.com/winfx/2006/xaml/presentation,而这个命名空间将在整本书中使用。
(1)System.Windows
(2)System.Windows.Automation
(3)System.Windows.Controls
(4)System.Windows.Controls.Primitives
(5)System.Windows.Data
(6)System.Windows.Documents
(7)System.Windows.Forms.Intergration
(8)System.Windows.Ink
(9)System.Windows.Input
(10)System.Windows.Media
(11)System.windows.Media.Animation
(12)System.Windows.Media.Effects
(13)System.Windows.Media.Imaging
(14)System.Windows.Media.Media3D
(15)System.Windows.Media.Media3D
(16)System.Windows.Media.TextFormatting
(17)System.Windows.Navigation
(18)System.Windows.Shapes
因为这是一个多对对一的映射,WPF的设计者需要保证不要引入两个相同名称的类,虽然这些类是放在不同的.NET命名空间的。
四、属性元素:即用属性来代替属性特性。属性值被设置为XML而不是XML特性。
属性元素中的句点用于区分对象元素(Object element)和属性元素(property element),他们总会以“类型名称.属性名称”的形式出现,并且还总会包含在类型名对象元素中,但是这些属性元素没有自己的特性。
属性元素,也可以用于简单的属性值。
五、类型转换器
<Button.Background>
White
</Button.Background>
System.Windows.Controls.Button b = new System.Windows.Controls.Button();
//b.Context = "OK";
b.Background = System.Windows.Media.Brushes.White;
上面的两个代码段的效果是相同的,但是这里有一点:White怎么能与Background相等呢?这里涉及到了类型转换器。
上述示例中提供了一些如何利用字符串设置XAML属性值的一些细节,这些属性的类型既不是String,也不是Object类型,在这种情况下:XAML编译器或者解释器需要寻找一种类型转换器,该类型转换起知道如何将一个字符串表达式转换为想要的数据类型。
WPF提供了许多常用的数据类型转化器(例如:Brush,Color,FontWeight,Point),他们都是继承与TypeConverter类。(例如:BrushConverter,ColorConverter),你也可以为自定义的数据类型编写列转换器,与XAML语言不同,类转换器支持不区分大小写的字符串。
六、标记扩展
标记扩展就像是类型转化器一样,可用于扩展XAML的表达能力。他们都是在运行时计算字符串特性 的值,(除了一些内建的、为提高性能而在编译时计算的标记扩展),并生成一个合适的基于字符串的对象。
但与类型转化器不同的是,标记扩展是通过XAML显示实现的,一致的语法调用的,因此标记扩展是扩展XAMl的最好的方式。
只要将特性值有一对“花括号”括起来,XAML编译器或者是解释器就会把它认作是一个“可扩展标记值”,而不是一个普通字符串,或者一些其他需要类型转换的东西。
<Button xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml"
Background = "{x:Null}"
Height = "{x:Static SystemParameters.IconHeight}"
Content = {Binding Path = Height,RelativeSource ={RelativeSource Self}}/>
每一个花括号中的第一个标识符是标志扩展类的名称。按照惯例:这样的类的名称都以Extension后缀结尾。但是当你在XAML中使用它时,可以不使用该后缀。这个例子中NullExtension我们看到的是x:Null,StaticExtension我们看到的是x:static.
NullExtension 和 StatictExtension 都是System.Windows.Markup命名空间的类,因此必须使用x来定位他们。Binding 是在System.Windows.Data命名空间下,因此它在XML默认的命名空间下就可以找到。
如果扩展支持,可以使用逗号来分割参数来指定他们的值。
定位参数(在本例中的SystemParameters.IconHeight)是被作为字符串参数传入扩展类的构造函数中。命名参数如(本例中的Path 和RelativeSource )可以用来在以构造好的扩展对象上设置相应的名字的属性。这些属性值可以是标记扩展值自己(使用潜逃的花括号,如RelativeSource)、也可以是普通的文本值,也可以是通过普通类型转换的过程。
还有在上述的例子中的一个特殊情况:NullExtension允许设置Background为NULL,但是BrushConvertor和其他类型转换器都不支持这种情况。
StaticExtension允许使用静态属性、字段、常量和枚举,而不使用XAML编写的硬编码值。
因为扩展标记是有默认构造函数的类,它们可以与属性元素一起使用。
<Button xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml">
<Button.Background>
<x:NULL>
</Button.Background>
<Button.Height>
<x:Static Member = "SystemParameters.IconHeight" />
</Button.Height>
<Button.Content>
<Binding Path = "Height">
<Binding.RelativeSource >
<RelativeSource Mode = "Self" >
</Binding.RelativeSource >
</Binding >
</Button.Content>
</Button>
上述转换之所以能够执行是因为:这些扩展标记都有与形参化的构造函数的实参【使用属性特性语法定位实参】对应的属性。例如:StaticExtension 有一个Member属性、与之前传入到形参化的构造函数中的实参是一个意思。RelativeSource 有一个对应对应于构造函数实参的Mode属性。