声明: 本译文仅供学习讨论,禁止用于商业用途,否则后果自负
我们在第一章里提到了XAML。XAML是一种很重要的语言,它可以将图形设计与开发工程很好的集成到一起。不管你是不是要进行图形设计的工作,都必要熟悉XAML语言.原因如下:
- XAML可以很容易地展现用户界面和物体的层次。
- 使用XAML时推荐将前台的展现代码和后台的逻辑代码分离。这样构建出的程序有很好的可维护性。即使你是自己单独开发也应该这样做
- 可以直接将XAML代码复制到XamlPad工具中(SDK提供的一个工具),无需编译即可显示结果
- 所有WPF相关的工具都会用到xaml
所以本章将深入介绍XAML的机制和语法,并提供相关代码.如果掌握了这些背景知识,不但有利于理解后面章节的代码示例,而且还能理解设计每个API的原因
XAML定义
XAML是比较简单的声明性编程语言,可以构造和初始化.NET对象。.NET Framework 3.0可以解析和编译XAML,并提供一个单独的插件,可以在ie内浏览xaml文件。
XAML实际上是一种.NET 的API.所以不要将它和HTML,Scalable Vector Graphics(SVG)或其他格式化语言进行比较。XAML是基于XML语法的,它也有自己的关键字,不能随意定义元素。所以 不能脱离WPF框架而谈XAMl,就像不能只说C#而不说.NET一样。
XAML和WPF之间的关系可能会让人很困惑。首先声明的是XAML和WPF是相互独立的。虽然XAML最初是为WPF设计的,但由于其天然的多用性,XAML也应用在其他技术上(例如WF).甚至只要愿意,可以将XAML应用到任何.NET技术上。XAML的所有功能都可以由.NET语言代替,但反之则不行。我们完全可以用.NET语言代替XAML来编写WPF程序,但由于XAML本身具有很多的优点,所以很少会出现不使用XAML的情况
元素和属性
XAML规范定义了自身和.NET命名的空间,类型,属性,事件的映射规则,并对应到了xml的命名空间,元素和属性。下面分别使用XAML和c#声明了一个WPF的Button控件,
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”;
虽然两段代码是等效的,但只有那段xaml的文件可以被ie浏览:你会看到Button控件填充满了整个浏览器(如 2.1)
FIGURE 2.1 A simple WPF Button declared
in a .xaml file.
在XAML中声明元素和在.NET中实例化相应对象的效果是相同的。同样地,XAML中的属性和事件也都会在.NET中有所对应。下面的代码用XAML和C#设置了Button的Content属性并注册了Click事件。
XAML:
<Button xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
Content=”OK” Click=”button_Click”/>
C#:
System.Windows.Controls.Button b = new System.Windows.Controls.Button();
b.Click += new System.Windows.RoutedEventHandler(button_Click);
b.Content = “OK”;
上面的代码需要名为button_Click的方法。也就是说XAML无法再像图 2.1那样正确显示了。我们将在后面的"Compilation: Mixing XAML with Procedural Code"演示XAML和代码协同工作。注:XAML和c#一样区分大小写。
Order of Property and Event Processing
至于多个属性之间被设置的顺序(或事件),这决定于各个属性/事件在XAML的顺序。
命名空间
现在最神秘的地方恐怕就是之前XAML示例中的命名空间"http://schemas.microsoft.com/winfx/2006/xaml"是如何映射到.NET的System.Windows.Controls命名空间。实际上这种映射是在WPF程序集中使用多个XmlnsDefinitionAttribute的一个硬编码行为。
XAML文件中的根元素至少需要指定一个命名空间来限定自身或子元素。当然,也可以在为元素或子元素添加多个命名空间,只不过这些命名空间的前缀必须唯一!下面的例子在第二个命名空间前加入了前缀"x"(使用xmlns:x来区别之前的xmlns)
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
上面的xaml命名空间对应的.NET的System.Windows.Markup命名空间,同时也定义了一些编译和解析的指令。这些指令一般是XML元素的属性,和XAML元素的属性有些相像,但实际上并不是。本章的”XAML Keywords“部分会提供关键字列表,您可以在那里查阅相关的信息
使用"http://schemas.microsoft.com/winfx/2006/xaml/presentation"作为默认的命名空间,而将用x作为前缀的"http://schemas.microsoft.com/winfx/2006/xaml"作为第二命名空间不过是约定俗成。这有些像在c#中使用"using System;"指令.您也可以自己写下面这样一个xaml文件,效果实际上是相同的:
<WpfNamespace:Button
xmlns:WpfNamespace=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
Content=”OK”/>
考虑到代码的可读性,第一个命名空间不要使用前缀,其余的命名空间应尽量使用简短的前缀。
DIGGING DEEPER
XAML的"http://schemas.microsoft.com/winfx/2006/xaml/presentation" 命名空间对应的.NET的命名空间:
. System.Windows
. System.Windows.Automation
. System.Windows.Controls
. System.Windows.Controls.Primitives
. System.Windows.Data
. System.Windows.Documents
. System.Windows.Forms.Integration
. System.Windows.Ink
. System.Windows.Input
. System.Windows.Media
. System.Windows.Media.Animation
. System.Windows.Media.Effects
. System.Windows.Media.Imaging
. System.Windows.Media.Media3D
. System.Windows.Media.TextFormatting
. System.Windows.Navigation
. System.Windows.Shapes
由于这是一个"多对一"的映射,所以要避免引用位于不同命名空间下的具有相同名称的类。
属性元素 (Property Elements)
本书的第一章曾经提到:元素之间的相互组合是WPF的一大特色。图2.1中的Button已经说明了这一点。实际上Button中内容并不仅仅限于文本,还可以放置其他任意内容。下面的代码就绘制了一个录音机的停止按钮:
System.Windows.Controls.Button b = new System.Windows.Controls.Button();
System.Windows.Shapes.Rectangle r = new System.Windows.Shapes.Rectangle();
r.Width = 40;
r.Height = 40;
r.Fill = System.Windows.Media.Brushes.Black;
b.Content = r; // Make the square the content of the Button
Button的Content属性的类型为System.Object,可以对其赋值任意类型。上面的代码将一个40*40大小的矩形赋值给Button。效果如图2.2
上面的代码相当简洁,那么怎样用XAML中的属性完成呢?怎样才能构建上面c#代码那样的矩形的字符串然后赋值给Content属性呢。实际上并不需要构建字符串,XAML提供一套为复杂属性赋值的语法:属性元素(property elements). 代码如下:
<Button xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”>
<Button.Content>
<Rectangle Height=”40” Width=”40” Fill=”Black”/>
</Button.Content>
</Button>
上面的代码中没有使用xml属性(attribute)给Content属性赋值,而是使用了一个xml元素。Button.Content不是对象元素(object elements)而是一个属性元素(property elements).属性元素附属于对象元素,格式为"类型名称.属性名称"(TypeName.PropertyName),并且不能再包含属性(attribute)
属性元素不仅可以用于复杂属性的赋值,还可以用于简单类型的属性赋值。下面的代码分别用属性(attributes)和属性元素两种方式为Button控件的Content属性和Background属性赋值,两者是等效的。
attribute
<Button xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
Content=”OK” Background=”White”/>
property elements
<Button xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”>
<Button.Content>
OK
</Button.Content>
<Button.Background>
White
</Button.Background>
</Button>