- <Window>
- <Grid>
-
- </Grid>
- </Window>
XAML是一种声明式语言,当你看见一个标签,就证明你声明了一个对象,对象之间的关系要么是并列,包含全都体现在标签的关系上。
下面的代码就是<WIndow>标签的Atrribute。
- x:Class="WpfApplication2.Window2"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="Window2" Height="300" Width="300"
其中Title、Width、Height一看就知道和Window的Property对象对应的。中间两行(即两个xmlns)实在声明名称空间。最上面一行是在使用名为class的Attribute,这个Attribute来自于X:前缀所对应的名称空间。下面仔细解释。
前面已经说过,XMAL语言是从XML语言派生而来的。XML有一个功能就是可以在XML文档的标签内使用xmlns特征来定义名称空间(NameSpace),XML也就是XML--NameSpace的缩写。定义名称空间的好处就是,当来源不同的类重名时,可以使用名称空间加以区分。xmlns特征的语法如下:
xmlns后可以跟一个可选的映射前缀,之前用冒号隔开。如果没有写可选映射的前缀,那就意味着所有来自这个名称空间的所有标签都不用加这个前缀,这个没有映射的命名空间称为“默认的命名空间”,默认名称空间只能有一个,而且应该选择其中使用最频繁的名称空间来作为默认命名空间。在上面的例子中,<Window>和<Grid>来自于第二行声明的默认命名空间,而第一样的CLASS特征则来来自于三行的中x:前缀对应的名称空间。这里可以做一个有趣的小实验:如果给第二行声明的名称空间加一个前缀,例如n,那么代码必须要改成一下形式编译才能通过:
- <n:Window x:Class="WpfApplication2.Window2"
- xmlns:n="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="Window2" Height="300" Width="300">
- <n:Grid>
-
- </n:Grid>
- </n:Window>
XAML中引用外来程序集和其中.NET名称空间的语法和C#是不一样的。在C#中,如果想使用System.Windows.Control名称空间内的Button类,需要先把包含
System.Windows.Control名称空间的程序集PresentationFramework.dll添加引用到项目中,然后再用C#代码顶部写上一句:using System.Windows.Control;。在XAML中做同样的事情也需要添加对程序集的引用,然后再在根元素的起始标签中写上一句:xmlns:c="clr-namespace:System.Windows.Control;assembly=PresentationFramework"。c是映射的前缀,换成其它字符串也可以。因为button来自前缀为c的命名空间,所以在使用button的时候就要使用<c:Button>....</c:Button>。 xmlns:c="clr-namespace:System.Windows.Control;assemble=PresentationFramework",这么长的一串字符串看上去的确有点恐怖,但不用担心,VS2008中有自动提示功能。
在VS2008自动提示的顶部,你会看到几个像网站地址的几个名称空间,其中就包含例子代码中的那两行。为什么名称空间看上去想一个网站地址呢。其实把它copy到浏览器地址栏尝试跳转也不会打开网页。这里只是XAML解释器的一个硬性编码(hard-coding),只要见到这些固定的字符串,就会把一系列的程序集和程序集中包含的名称空间引入进来。
默认引入的这两个名称空间格外的重要,它们对应的程序集和.net名称空间如下:
http://schemas.microsoft.com/winfx/2006/xaml/presentation对应:
System.Windows;
System.Windows.Automation;
System.Windows.Control;
System.Windows.Control.Primitives;
System.Windows.Data;
System.Windows.Document;
System.Windows.Forms.Intergration;
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.TextFormmatting;
System.Windows.Navigation;
System.Windows.Shapes;
也就是说你可以在XAML中可以直接使用这些CLR名称空间下的类型(因为默认XML名称空间前没有前缀)。
http://schemas.microsoft.com/winfx/2006/xaml则对应一些与XAML语法和编译相关的CLR名称空间, 使用这些名称空间中的类型需要加上前缀x,因为它们被映射到x的XML名称空间中。
从这两个名称空间的名字和它所对应的.NET程序集上,这个不难看出,第一个空间名称对应的是绘制UI相关的程序集,是表示(Presentation)层面上的东西;第二个名称空间则对应着XAML解析处理相关的程序集,是语言层面上的东西。
还剩下x:Class="WpfApplication2.Window2"这个Attribute。x前缀说明这个Attribute来着于x映射的名称空间----前面我们解释过,这个名称空间对应XAML解析功能的。x:Class,顾名思义他与类有一些关系,是何种关系呢,让我们做一个有趣的实验:
首先,x:Class="WpfApplication2.Window2"这个Attribute删掉,再到Windows.xaml.cs文件里,把构造中对InitalizeComponent方法的调用也删掉。编译程序,你会发现,程序依然可以运行,为什么呢?打开App.xaml这个文件,你会发现这样一个Attribute------StartupUri="Window1.xaml",是它告诉编译器把Window1.xaml作为程序启动的主窗体。也就是说,只要Windows1.Xaml能够被解析为一个窗体,程序就能够运行。
然后只恢复x:Class="WpfApplication2.Window2"这个Attribute(不恢复InitalizeComponent方法的调用)。编译之后仍然可以运行,这是使用IL Disassembler(中间语言凡编译器)打开项目的编译结果,你会发现在由项目编译生成的程序集里面包含一个名为Window2的类,如下图所示
这说明,XAML这个Attribute的作用是当XAML解析器将它的标签解析成C#类之后,这个类的类名是什么。这里已经触碰到XAML的本质。前面我们已经看到,事例代码的结构就是使用XAML语言直观的告诉我们,当前的窗体是一个<Window>里面嵌入了一个<Grid>。如果是使用C#完成同样的设计呢?显然,我们不可能去更改Window这个类,我们能做的是从Window派生一个类,再为这个类添加一个Grid类型的字段,然后把这个字段初始化的时候赋值给派生类的类容属性。代码看起来大概是这样:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Shapes;
-
- namespace WpfApplication2
- {
-
-
-
- public partial class Window2 : Window
- {
- private Grid grid;
- public Window2()
- {
- grid = new Grid();
- this.Content = grid;
- }
- }
- }
最后让让我回到最初的代码。你可能会问:在XAML里面有
x:Class="WpfApplication2.Window2",在Windows2.xaml.cs里面也声明了Window2这个类,难道他们不会冲突吗?仔细看看Windows2.xaml.cs中Window2的声明就知道了----在声明的时候使用的是partial关键字,这样,这样由XAML中解析成的类和C#文件里面定义的部分就合二为1了,正是由于这种partial机制,我们可以把逻辑代码留在.cs文件里,用C#语言来实现,而把那些声明及布局UI元素的代码分离出去,实现UI和逻辑分离,并且,用于绘制UI的代码(如声明控件类型的字段,设置它们的外观和布局等)也不必再使用C#语言,使用XAML和XAML编辑工具就可以轻松搞定。 至此,你应该对这个简单的XAML程序了然于胸了。