4.1 XAML的根元素
我们知道XML文件总是从一个单一元素开始的,在这个单一元素的里面可以放置任意个子元素。子元素中又可以包含其他子元素,如此下去,整个XML文件就像一棵倒挂的树。开始的这个单一元素就叫做根元素,XAML也遵循XML这一规范。
通常XAML的根元素有两个:一个是Window,说明这是一个桌面应用程序;另一个是Page,主要用在互联网应用程序中,有时候桌面应用程序也用到Page。
- <Window x:Class="Yingbao.Chapter2.Window1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml
- /presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="送元二使安西" Height="300" Width="300" >
- <StackPanel Orientation ="Vertical" >
- </StackPanel.LayoutTransform>
- </StackPanel>
- </Window>
上面这段XAML为桌面应用程序,其根元素为Window。
- <Page x:Class="Yingbao.Chapter2.MyFrirstWebPage"
- xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
- xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml Title="网页"
- Height="80" Width="300">
- <StackPanel Orientation ="Horizontal " >
- </StackPanel>
- </Page>
上面这段为XMAL网页,它的根元素为Page。
由此可见,XAML网页和桌面程序的区别只是XAML根元素的不同(Silverlight 在使用CLR对象时目前还有些限制,但从大的方面来说两者的编程模型是一样的)。
XAML编译器并不限制根元素的类型,在一般WPF应用程序中,常见的根元素除了上面的Window和Page之外,还有FlowDocument,Application和Grid等。
4.2 XAML命名空间(NameSpace)
长期以来,各大公司或个人开发了大量面向对象的软件。在C#或C++里,为了区分模块间的同名类,我们引入命名空间。本书采用的命名空间规则是笔者本人的名字加上章节名。比如第3章中的例子,都放在Yingbao.Chapter3这个命名空间中;而第4章中的例子,都放在Yingbao.Chapter4这个命名空间中;这样,即使有两个在第3章和第4章同名的类,比如TreeView。那么可以用Yingbao.Chapter3.TreeView和Yingbao.Chapter4.TreeView来区分用的究竟是哪个类。
同样的道理,在XAML中也使用命名空间这个概念。 XML的命名空间,则用xmlns来表示,例如前面的例子:
- <Window x:Class="Yingbao.Chapter2.Window1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="
- 送元二使安西" Height="300" Width="300" >
在这个例子中,使用了两个命名空间,一个是http://schemas.microsoft.com/winfx/2006/xaml/presentation;另一个是http://schemas. microsoft.com/winfx/2006/xaml。注意,XAML中的命名空间和.NET的命名空间密切相关,但XAML的命名空间和.NET的命名空间之间并不是一一对应的,而是一对多的关系,即一个XAML命名空间对应多个.NET的命名空间。这样做的好处是,不必在XAML中书写过多的命名空间。一般来说在XAML里使用这两个命名空间就包括了WPF中所有的命名空间。
这种让一个XAML命名空间对应多个.NET命名空间的做法不仅微软可以用,任何软件开发人员也都可以使用。比如我可以把Yingbao.Chapter2和Yingbao.Chapter3两个命名空间合并为一个XAML命名空间,方法是在项目的AssemblyInfo.cs文件中使用XmlnsDefinition属性:
- [assembly: XmlnsDefinition("http://Yingbao.Com/WPFExample",
- "Yingbao.Chapter3")]
- [assembly: XmlnsDefinition("http://Yingbao.Com/WPFExample",
- "Yingbao.Chapter4")]
这里我把Yingbao.Chapter3和Yingbao.Chapter4两个.NET命名空间合并到http://Yingbao.Com/
WPFExample 这一个命名空间中。注意:这里的http://Yingbao.Com 并不是真的有一个这样的网址。
WPF使用这一技术,把所有WPF类命名空间映射到一个XAML命名空间:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
注意xmlns后面没有冒号,这表示WPF在XAML中默认命名空间。另一个WPF中常用的命名空间是:xmlns:x=http://schemas.microsoft.com/ winfx/2006/xaml,它包含了XAML的某些特定功能,比如控制XAML编译器等。
如果要在XAML中使用非WPF命名空间中的类,那么你就要在XAML中引入相应的命名空间,例如,我们要在Window中使用ADO.NET中的类,我们可以直接在XMAL中引入System.Data命名空间:
- <Window x:Class="Yingbao.Chapter2.Window1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml
- /presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:ado="clr-namespace:System.Data;assembly= System.Data,
- Version=2.0.0.0,Culture=Meutral,PublicKeyToken=b77a5c561934e089"
- Title="送元二使安西" Height="300" Width="300" >
可以使用同样的方法在XAML中引用笔者自己开发的类,例如在本书第11章中的例子:
- <Window x:Class="Yingbao.Chapter11.BookBanding.BookWindow"
- xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:src="clr-namespace:Yingbao.Chapter11.BookBanding"
- Title=".NET对象绑定到界面元素" Height="200" Width="340" >
这里xmlns:src就是在XAML中引入Yingbao.Chapter11.BookBanding命名空间。
4.3 XAML和代码分离技术(code behind)
和ASP.NET一样,XAML也使用代码分离技术。WPF应用程序一般由两大部分组成,一部分用XAML描述UI元素在界面上的位置,大小等;另一部分用来处理程序的逻辑、对传递事件的反应,等等。
让我们来看一看前面的例子:
- <Window
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml
- /presentation"
- xmlns:x=" http://schemas.microsoft.com/winfx/2006/xaml"
- x:Class="Yingbao.Chapter2.Window1"
- Title="送元二使安西" Height="300" Width="300" >
XAML在编译这个XAML时,在Yingbao.Chapter2命名空间中创建一个Window1的类。这是由XAML中的x:Classs说明的,前缀x是XAML的命名空间 (xmlns: x= "http://schemas.microsoft.com/
winfx/2006/xaml ")。属性x:Class确定要产生的类名,如这里的Window1。其次,XAML在产生类Window1时,把元素名Window作为Window1的基类。若我们在Visual Studio里创建XAML,Visual Studio会自动产生下面的部分类代码:
- namespace Yingbao.Chapter2
- {
- public partial class Window1 : System.Windows.Window
- {
- public Window1 ()
- {
- InitializeComponent();
- }
- }
- }
显然,Window1从Window类中派生出来。
在这个例子中,若我们省去x:Class属性,那么根元素就是Window类,而不是Window1类。代码分离技术提倡我们使用派生类。
4.4 子元素
在XAML中,除了根元素之外的所有元素都是子元素。根元素只有一个,而子元素理论上可以有无限多个。子元素又可以包含一个或多个子元素,某个元素可以含有子元素的多少由WPF中具体类决定。排版类元素可以包含多个子元素,而内容控件只能含有一个子元素。让我们来看一个例子:
- <Window x:Class="Yingbao.Chapter2.DockPanelProperties"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="停靠面板属性" Height="500" Width="600" >
- <DockPanel Background="White">
- <TextBlock FontSize="16" FontWeight="Bold" DockPanel.Dock="Top"
- Margin="20,0,0,10">停靠面板属性</TextBlock>
- <TextBlock DockPanel.Dock="Top" Margin="0,0,0,10"
- TextWrapping="Wrap">
- 选择下面的控件及其停靠属性,观察控件在停靠控制面板中的位置
- </TextBlock>
- </DockPanel>
- </Window>
在这个例子中,Window是XAML的根元素,其中含有DockPanel这个子元素。由于Window是一个内容控件,它只能含有一个子元素。DockPanel是一个排版控件,它可以含有任意多个子控件,这里,我在DockPanel中放入了两个TextBlock。
如果我们用C#来写这些元素之间的关系,上面的程序可以改写为:
- namespace Yingbao.Chapter2
- {
- public partial class DockPanelProperties :
- System.Windows.Window
- {
- public DockPanelProperties()
- {
- InitializeComponent();
- DockPanel dp = new DockPanel();
- dp.Background = "White";
- this.Content = dp;
- TextBlock tb = new TextBlock();
- // 设置tb属性
- dp.Children.Add(tb);
- TextBlock tb = new TextBlock(); //下一个TextBlock
- // 设置tb属性
- dp.Children.Add(tb);
- }
- }
- }
从C#程序,我们可以清楚地看出Window、DockPanel和TextBlock之间的关系。有关Window、DockPanel和TextBlock,本文后面章节将会详细介绍,在这里,只要了解XAML中子元素之间的关系就可以了。
参考:http://book.51cto.com/art/201001/179677.htm