嵌套标签内。每个元素的命名都是可读的。工程文件通过命令行传递给msbuild.exe工具。MSBuild位于框架文件夹Windows\Micorsoft.NET。下列简单的命令会生成基于Events.Proj工程文件的可执行文件:
msbuild.exe Events.proj
除非你想练习MSBuild工具,否则不应该过多关注它。正如前面所提,Visual Studio 的Whidbey版本与Longhorn SDK很好地集成在一起,编译Longhorn程序时只需点击普通工具条上按钮或者按F5键。Figure 5显示了Figure 2代码的运行结果。在应用程序树层次里,只有一个蓝色面板是可见并显示有文字。程序树层次比观察Figure 5得到的表面印象要稍稍复杂。树根节点是一个包含DockPanel对象的 窗体。DockPanel是所有用户界面元素的最外层容器,并包含一个孩子FlowPanel,这个孩子节点相应也包含一个Text对象。文本通过Text类的实例 绘制。你应该注意到XAML标签有几个属性可以控制它们的外观。更重要的是,它们支持ID属性,而ID属性提供了运行时识别。无论何时你在控件区域内点击,关联 FlowPanel 类的 MouseLeftButtonDown 事件就被触发。当点击后,OnLeftMouseDown 事件
处理程序代码被调用。可以看到,流动面板(flow panel)的宽度和高度放大一倍,文字也改变了。再点击,又恢复到原大小。

Figure 5 运行程序
尽管谁也无法阻止你编写纯程序码的程序,但是,使用XAML文件,你能较容易描述并模板化程序的用户界面。
XAML语言
四种主要元素类别组成XAML词汇表——面板(panel)、交互控件(interactive control)、文档关联元素(document-related element)和图形(graphic shape)。边框元素(border element)也很重要,尽管它不属于上面任何一类。技术上看,它是一个“装饰品”,以提供细布局细节,其仅容纳一个子元素,但增加了视图效果。XAML中,面板处理页面布局,并担当其他元素的容器。面板管理被包含元素的绘制如大小和位置,排列它们的内容。Longhorn中一共有6个内置的面板类,但是开发人员可以通过定制面板行为来创建自己的面板。这些预定义的面板类是Canvas、DockPanel、FlowPanel、GridPanel、Table和TextPanel。Figure 6简单描述了它们。
Canvas是这些面板中唯一支持显示设置元素位置的面板。其所有孩子元素的描述都开始于一个固定的位置,然后紧接着大小。如果两个元素重叠,则最后一个绘制的元素获胜,它覆盖其他元素区域。注意描述时所用的坐标都是相对于Canvas,即,(0,0)表示面板 区域的最左上象素。下面是一个canvas对象例子。
<Canvas xmlns="http://schemas.microsoft.com/2003/xaml"
Height="600" Width="800">
<Border Background="red"
Canvas.Top="0px" Canvas.Left="0px"
Height="100px" Width="100px" />
<Border Background="green "
Canvas.Top="100px" Canvas.Left="100px"
Height="100px" Width="100px" />
<Border Background="blue"
Canvas.Top="50px" Canvas.Left="50px"
Height="100px" Width="100px" />
</Canvas>
同样是包容其他元素,DockPanel则有不一样的行为。这种面板所有孩子相互之间都是水平或垂直地浮动。既然如此,它们的位置只是相对于上一个控件,并不需要坐标。DockPanel适合于创建一个按钮条,如同工具条那样。这里有一个例子:
<Border xmlns="http://schemas.microsoft.com/2003/xaml"
Background="black" >
<DockPanel>
<Button DockPanel.Dock="Left" Width="50px" Height="32px">
Open
</Button>
<Button DockPanel.Dock="Left" Width="50px" Height="32px">
Save
</Button>
<Button DockPanel.Dock="Left" Width="50px" Height="32px">
Print
</Button>
</DockPanel>
</Border>
第一个按钮被放置在面板的左侧,其他按钮都与紧邻的按钮水平对齐(见Figure 7)。
Figure 7 按钮布局
FlowPanel允许孩子元素在可用空间内以任何方式流动。这种面板包含了处理显示内容超过面板宽度的逻辑。既然 如此,则依照这个对象的配置,超出的内容会换行显示或被裁减掉。下面的XAML例子示范了FlowPanel如何将逻辑上是一单行的内容截断并换行。四个square元素被一个大一些的元素包容。小square的宽度之和大于容器 元素的宽。因为所有小square不适合于放在一行中,所以此行被截断,最后一个square移到下一行。注意默认的面板流向是从左到右,从顶端到底端:
<FlowPanel xmlns="http://schemas.microsoft.com/2003/xaml"
Width="250px" Height="250px">
<Border Background="red" Width="75px" Height="75px" />
<Border Background="green" Width="75px" Height="75px" />
<Border Background="blue" Width="75px" Height="75px" />
<Border Background="orange" Width="75px" Height="75px" />
</FlowPanel>
GuidPanel是一个轻量级元素,用于布置具有格子风格的对象和生成简单的表格。GridPanel允许你将任意控件安置在一个矩阵似的行和列中,但是总体上 只具备一个有限的特征集。更复杂的表格可以通过Table面板生成,它们具有很多高级功能。Table面板的结构由多行组成。你能为页头或页脚定义一组行,也能插入不同设置的行。这种面板的布局能力可以让你创建相当复杂的 数据显示表格。
最后,当需要复杂的文本布局支持时,TextPanel是理想的选择。然而,对于基本的文本支持,Text元素将是更好的选择,因为它消耗更少资源(和更少的能力)。
MSAvalon.Windows.Controls名字空间将所有负责用户交互的控件组合起来。例子中属于这个名字空间的类,如Button、ListBox和CheckBox,都是老熟人,一些新的如ContextMenu、PageViewer和RadioButtonList也属于这个名字空间。用户交互元素的基类是Control,它提供一组公共的属性和方法。
Figure 8 页面查看器
特别地,PageViewer控件提供用于查看在线文档的用户界面,封装了分页和页面导航功能。下面的例子生成一个页面查看器,其占据整个客户区。页面查看器分页显示了PageViewer标签Source属性指定文件的文本:
<DockPanel ID="root" xmlns="http://
schemas.microsoft.com/2003/xaml"
xmlns:def="Definition">
<Text DockPanel.Dock="Top">See a
PageViewer control in action below.
</Text>
<PageViewer DockPanel.Dock="Top"
Source="Sample.xaml" Height="80%" Width="80%"/>
<Button DockPanel.Dock="Top" Width="50%">OK</Button>
</DockPanel>
有趣的是,通过PageViewer控件显示的源文件不能是纯文本、RTF或HTML文件。至少目前,它必须是一个包含普通ASCII文本的XAML文件,这些文本通过支持分页的Avalon控件包装起来。Avalon是Longhorn中新的显示子系统(presentation subsystem)的代号(请看本期Charles Petzold的文章)。例如,看看TextPanel类:
<TextPanel ID="root" xmlns="http://schemas.microsoft.com/2003/xaml">
text to show goes here
</TextPanel>
保存这段代码片段到文件sample.xaml中,以运行早先的例子。记住xmlns名字空间是必须的。
MSAvalon.Windows.Documents名字空间中的类负责文档显示。总的看来,这些类就像是高级HTML标签的超集。你能看到一些如Block、Column、Heading和Footer类,也有CloumnGroup、RowGroup、HyperLink、List,还有更多。
在我所用的Longhorn预发布版本中,前面看到的Text类属于System.Windows.Controls名字空间。Text类支持多行和多种格式,包括粗体和斜体,字体大小和嵌套的孩子元素。在只需要简单文本场合中,Text是首选类,因为它是轻量级的并具备多种可用特色。
Longhorn显示模型通过使用XAML面板元素来绘制图像。面板提供许多大小和对齐属性,也可以控制边框、背景色和填充。
Longhorn中,图像是通过Windows Vector Graphics绘制出来。Windows Vector Graphics提供许多比GDI和GDI+更多好处,它是基于XML的图像标记系统,易于使用和重用。如果你是Scalable Vector Graphics的拥护者,你也会喜欢它。Windows Vector Graphics提供如椭圆、线、路径、多边形、PolyLine和矩形这些预定义图形,这些都从Shape类继承。这些元素从Shape继承了许多公共的属性,包括Stroke、StrokeThickness、Fill,外加其他 用于指定坐标和顶点的属性。这些图形能够被倾斜、旋转、平移、缩放。正如你能够指定图形的填充色和背景,你也能指定色彩灰度。下面例子设置了矩形填充属性为水平灰度,以红色开始以蓝色结尾。
<Rectangle xmlns="http://schemas.microsoft.com/2003/xaml"
Canvas.Top="10" Canvas.Left="10"
Fill="HorizontalGradient Red Blue"
RectangleLeft="0" RectangleTop="0"
Width="50" Height="50"/>
生成简单应用程序
通过使用XAML语言,你能快速有效构造一个用户界面原型。我敢打赌:到Longhorn发布后,大量的开发工具会升级(或从开始就内置)以完全支持XAML“所见即所得”(WYSIWYG)属性。Longhorn预览版本已经包含一些Visual Studio .NET Whidbey版本的扩展。下面让我们看一个严格的、可交互的程序。你会很快发现同编写一个Windows窗体程序没有多大的不同,也会惊喜的发现现有的.NET技巧多么适用于Longhorn。Figure 9中,你可以看到一个只包含文本框和上下文菜单的简单程序。文本框在XAML文件中定义,上下文菜单在空闲时创建。完整代码见Figure 10。
Figure 9 上下文菜单
Longhorn中,所有程序都需要实例化Application类。这个对象是Longhorn应用程序模型的核心。然而,Application对象仅提供基本 的程序支持,典型被用于需要低资源消耗和不用导航功能的程序。实际使用中,更多的Longhorn程序采用相近的NavigationApplication对象,它继承于Application并增加对导航的支持。
NavigationApplication对象支持许多方法、属性和事件,通过它们可以组合多个XAML页面到一个单个程序中。某种意义上,基于简单Application类的Longhorn程序相当于Win32中基于对话框程序。同样,可以将支持导航的程序比作“完全 的Win32程序”,许多窗体 构成了这种Win32程序的整个功能。下列代码显示使用导航的例子。
myApp = NavigationApplication.Current;
win = (Navigation.NavigationWindow) myApp.Windows[0];
...
private void Button_Back(Object sender, ClickEventArgs e)
{
// If possible, go to the previous window
if(win.CanGoBack())
win.GoBack();
}
通过Application(或NavigationApplication)静态Current属性,可以得到application对象的引用。前面的例子显示如何获取栈中第一个窗体的引用。Button_Back事件处理函数检查前一个窗体对象是否存在,如果存在,则以类似浏览器方式转回原窗体。
下一个例子描述如何通过继承并覆盖OnStartingUp方式,定制一个具备导航能力程序的启动行为。下列代码段覆盖OnStartingUp,以实现当程序启动时创建并显示一个导航窗体的功能。
public class MyApp : NavigationApplication
{
NavigationWindow win;
...
protected override void OnStartingUp(StartingUpCancelEventArgs e)
{
win = new NavigationWindow();
// Add elements to the window
...
navWin.Show();
}
...
} 让我们回到Figure 9显示的例子程序。按照已论述过的知识,你应该要么选择Application要么选择NavigationApplication作为基类,因为程序打算使用单窗体,即“基于对话框”程序。命名为“Sample1”的工作类覆盖OnStartingUp方法并定义一些事件处理函数。必须覆盖OnStartingUp方法,因为它体现程序的初始化步骤,因此是在打开窗体前执行你自己代码的理想位置。
OnStartingUp中完成的操作是创建窗口,窗口内容是用XAML文件和codebehind类描述。XAML页面本身由控件或其他存在于层次树中的组件组成。决定页面如何绘制和表现行为的是:这些不同组件或称元素之间的关系。Figure 9中例子页面有一个给定大小和字体的文本框(TextBox)控件。文本框与事件ContextMenuEvent绑定。只要用户右键点击控件的客户区,事件就被触发。
事件handler创建一个ContextMenu对象(见Figure 10)。安置上下文菜单,设置图形属性,然后将它与父对象关联, 此父对象是一个文本框。值得注意的是,通过选择背景和背景色、边框和字体,Longhorn让你很容易定制菜单(也包括其他所有对象)的外观。不要被这样的事实愚弄:在Windows以前的版本做同样的事也很容易,当然包括.NET框架。Win32中,这种类型的定制需要许多编程工作,它决不简单。.NET框架中,封装类隐藏许多必须的代码到框架包中,仅暴露少数属性给用户。另一方面,在Longhorn中,控件的用户界面就像它看起来一样简单。
上下文菜单的元素通过MenuItem类创建。将它们与事件handler绑定 方式基本上与基于框架程序一样:
mia = new MenuItem[3];
for (int i=0; i<3; i++)
{
mia[i] = new MenuItem();
cm.Items.Add(mia[i]);
mia[i].Foreground = Brushes.Black;
}
mia[0].Header = "Lower Text";
mia[1].Header = "Upper case";
mia[2].Header = "Select all";
mia[0].Click += new ClickEventHandler(LowerCase);
mia[1].Click += new ClickEventHandler(UpperCase);
mia[2].Click += new ClickEventHandler(SelectAll);
当某一个菜单项被点击时,事件handler开始执行,并使用传入的第一个参数获取源对象的引用:
public void LowerCase(Object sender, ClickEventArgs args)
{
MenuItem mi = (MenuItem) args.Source;
ContextMenu menu = (ContextMenu) mi.Parent;
TextBox thisTextBox = (TextBox) menu.PlacementTarget;
thisTextBox.Text = thisTextBox.Text.ToLower();
}
为了获取TextBox,必须沿着对象树上溯。首先,得到MenuItem,然后ContextMenu,最后就可以获取ContextMenu的拥有者,即TextBox。这时,修改TextBox的内容是很直接的。
结束语
Longhorn标志着Windows操作系统历史上的里程碑。它是第一个明确地基于受管代码设计的Windows版本。Longhorn更重要的特性在于新的程序模型;特别的是,在以前基于.NET框架和ASP.NET程序模型经验基础上,Longhorn的设计和实现达到了新的顶峰。
Longhorn程序全部由Application对象生成,能使你将多个标记页面组成一个连贯的程序。隐身于Longhorn程序后XAML语言的出现也是一个抽象水平的象征, 围绕它Longhorn程序模型才被设计出。Longhorn最终目标是让你一次编写程序,在不同场景多次部署它们,包括Web和基于客户机环境。
介绍一个只有少数人试验过的新平台的应用程序模型不是一份容易的任务。它甚至比你考虑将来哪些方面可能会显著改变更困难。依照这些内容,应该把这篇文章看作目前Longhorn一个快照和简单一瞥。
我已经将例子工程源码作成下载包,以便于你在Longhorn运行。你能通过在本文顶部的连接得到改工程源码。
原作者简介:
Dino Esposit 是一位讲师和顾问,他生活在意大利的罗马。他是Programming ASP.NET(Microsoft
Press)一书的作者。他目前大部分时间用于教授关于ADO.NET和ASP.NET课程和参加会议并演说。
Dino的联系方式:cutting@microsoft.com