分享
 
 
 

“Longhorn”应用开发部署初探(二)

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

作者:Dino Esposito

翻译:winsome zhong

三、XAML语言

XAML由四大类元素组成----面板(panels)、交互式控件(interactive controls)、文档对象(documents)和图形(graphic shapes)。另外边框(Border)元素也很重要,虽然它不属于四大类元素。在XAML中,Panel负责管理页面布局,并且是其他元素的容器,控制它们的大小、位置及内容的绘制方式等。Longhorn内建了6个Panel类--Canvas, DockPanel, FlowPanel, GridPanel, Table和TextPanel。但是开发人员可以创建自己的Panel,定制其绘制行为。

Canvas是面板中唯一支持坐标的,它上面的控件元素从一个固定的位置开始绘制,具有特定的尺寸。如果两个控件元素重叠,后绘制的那个将覆盖掉前一个。注意坐标是相对于Canvas的,(0,0)代表Canvas的左上角。下面是一个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上的所有控件元素彼此都是垂直或水平地dock在一起的,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>

结果如图6,第一个按钮在Panel的最左边,其它的按钮依次按水平排列。

图六 Button Layout

FlowPanel又是另一种方式,它使上面的控件沿着一个方向一个接一个的排列,当控件超出了Panel的宽度或高度,你可以设置让它折叠显示到下一行或把超出的部分截掉不显示。下面这个例子演示了FlowPanel是如何折叠显示的。FlowPanel上有4个方块(其实是Border),它们的width之和大于FlowPanel的width。因此不能在一行显示所有的方块,最后一个方块被显示在第二行。FlowPanel默认的排列方向是从左至右,从上到下:

<FlowPanel 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>

GridPanel是一个轻量级的布局管理器,它把上面的控件像网格一样进行布局,从而构造出一个简单的表格。GridPanel允许你在行或列上放上任意的控件,组合成一个控件矩阵。但是GridPanel的功能还是比较简单,要构造更为高级的表格,你可以使用Table panel。Table panel用于显示一些复杂的表格数据,它支持一些高级的表格特性比如Header、Footer、Column、Row Group等。

最后,TextPanel用于优化文本的显示,它支持一些比较复杂的文本格式。但是,对于基本的文本显示,用Text可能是一个更好的选择,Text用于显示没有格式的文本。

所有复责与用户交互的控件都在MSAvalon.Windows.Controls命名空间中。比如Button、ComboBox、ListBox、CheckBox、ContextMenu、RadioButtonList和PageViewer等。交互式控件的基类式Control,它提供了控件公用的属性和方法。比较特别的是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>

运行结果如图7

图七 Page Viewer

有意思的是Page Viewer不能显示纯粹的Txt、RTF或HTML,至少目前是这样。PageViewer的Source属性中指定的文件必须是一个XAML文件,该文件中被显示的ASCII文本还必须用支持分页的Avalon控件包裹(Avalon是Longhorn新的显示子系统的代号),比如TextPanel。把下面这段代码存为sample.xaml,做为上个例子中PageViewer显示的文件(注意其中的xmlns是必须的):

<TextPanel ID="root" xmlns="http://schemas.microsoft.com/2003/xaml/">

text to show goes here

</TextPanel>

命名空间MSAvalon.Windows.Documents中的类负责文档的显示。这些类的集合看上去像HTML标签的扩充,包括Block, Column, Heading, Footer,ColumnGroup, RowGroup, HyperLink和List这些类。

Longhorn使用Windows矢量图形(Windows Vector Graphics,简称WVG)来绘制图形内容,WVG比起GDI和GDI+来有很多优点,它是一个基于XML的图形系统,便于使用和重用,对SVG爱好者而言这是个好消息。WVG预定义的图形有Ellipse, Line, Path, Polygon, Polyline, 和Rectangle。它们都是Shape的子类。Shape可以倾斜、旋转和透明化。除了可以像以前一样使用纯色来作为背景外,你还可以指定渐进色的背景。下面这个例子使用水平渐进色来填充一个椭圆,从红色开始最后过渡到蓝色:

<Rectangle Fill="HorizontalGradient Red Blue"

RectangleLeft="150" RectangleTop="150"

Width="50" Height="50">

</Rectangle>

四、构建一个范例

使用XAML语言,你可以快速高效地设计用户界面。我敢保证到Longhorn发布时,许多完全支持所见及所得的XAML开发工具会被更新或被开发出来,目前发布的预览版的Whidbey中已经包括了一部分这方面的扩展。下面让我们来构建一个范例程序。你将看到这和编写Windows窗体应用并没有太大的不同,而且你也将马上惊奇的发现你已掌握的.NET的技能可以很好的被应用在Longhorn上。这个程序的用户界面如图8所示,包括一个文本筐和一个上下文菜单。文本筐是用XAML定义的,而上下文菜单是动态创建的。

图八 Context Menu

程序源码如下:

<Window

xmlns="http://schemas.microsoft.com/2003/xaml"

xmlns:def="Definition"

def:Class="Application2.Window1"

def:CodeBehind="Window1.xaml.cs"

Text="Application2" Visible="True">

<FlowPanel DockPanel.Dock="Fill">

<TextBox ID="input" Margin="10,10"

Background="LightCyan"

BorderBrush="black" FontFamily="verdana"

FontSize="16"

BorderThickness="1"

ContextMenuEvent="OnContextMenu"

Height="40" Width="360">Right-click to see a

context menu</TextBox>

</FlowPanel>

</Window>

// C# source file for the application

namespace MsdnLHSample

{

public partial class MyApp : Application

{

void AppStartingUp(object sender, StartingUpCancelEventArgs e)

{

Window mainWindow = new Window1();

mainWindow.Show();

}

}

}

// C# source file for the window

using System;

using MSAvalon.Windows;

using MSAvalon.Windows.Media;

using MSAvalon.Windows.Controls;

using MSAvalon.Windows.Documents;

using MSAvalon.Windows.Navigation;

using MSAvalon.Windows.Shapes;

using MSAvalon.Windows.Data;

namespace MsdnLHSample

{

// input is the textbox declared in the XAML

public partial class Window1 : Window

{

private void OnContextMenu(object sender, ContextMenuEventArgs e)

{

CreateMenu();

}

private void CreateMenu()

{

ContextMenu cm = new ContextMenu();

cm.FontFamily = "verdana";

cm.Background = Brushes.LightYellow;

MenuItem mi0 = new MenuItem();

mi0.Header = "Lower case";

mi0.FontSize = new FontSize(16);

mi0.Click += new ClickEventHandler(LowerCase);

cm.Items.Add(mi0);

MenuItem mi1 = new MenuItem();

mi1.FontSize = new FontSize(16);

mi1.Header = "Upper case";

mi1.Click += new ClickEventHandler(UpperCase);

cm.Items.Add(mi1);

MenuItem mi2 = new MenuItem();

mi2.Header = "Select All";

mi2.FontSize = new FontSize(16);

mi2.Click += new ClickEventHandler(SelectAll);

cm.Items.Add(mi2);

input.ContextMenu = cm;

}

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();

}

public void UpperCase(Object sender, ClickEventArgs args)

{

MenuItem mi = (MenuItem)args.Source;

ContextMenu menu = (ContextMenu)mi.Parent;

TextBox thisTextBox = (TextBox)menu.PlacementTarget;

thisTextBox.Text = thisTextBox.Text.ToUpper();

}

public void SelectAll(Object sender, ClickEventArgs args)

{

MenuItem mi = (MenuItem)args.Source;

ContextMenu menu = (ContextMenu)mi.Parent;

TextBox thisTextBox = (TextBox)menu.PlacementTarget;

thisTextBox.SelectAll();

}

}

}

前面提到过Longhorn中所有的应用程序都是Application类的一个实例。这个对象是Longhorn应用模型的核心。但是Application对象只提供了一些基本的功能,一般只用于一些低级的、不需要导航功能的程序。实际上大部分Longhorn应用程序使用的是Application的一个子类--NavigationApplication,这个对象增加了对导航的支持。NavigationApplication支持大量的属性、方法和事件,这使你可以把一大堆的XAML Page组合到一个应用程序中。做一个这样的比较可能更清楚些:基于Application类的Longhorn应用程序类似于Win32中基于对话筐的程序。而基于NavigationApplication的,可导航的的Longhorn程序则相当于一个完整的Win32程序,它包括众多的窗体,一起完成程序的功能。下面是一个如何在Page中导航的例子:

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事件中首先检查第一个窗体对象是否存在,如果存在就跳转过去。

下面的例子演示了怎样通过继承NavigationApplication并覆盖其OnStartingUp方法来定制程序启动时的行为:

public class MyApp : NavigationApplication

{

NavigationWindow win;

......

protected override void OnStartingUp(StartingUpCancelEventArgs e)

{

win = new NavigationWindow();

// Add elements to the window

......

navWin.Show();

}

......

}

让我们再回到图8的例子。根据我们刚刚的讨论,本例你既可以用Application作为基类,也可以用NavigationApplication,因为这只是一个单窗体的应用程序,我使用的是Application,程序中覆盖了Application的AppStartingUp方法,并且定义了几个事件处理器。AppStartingUp是进行系统初始化工作的理想地点。在AppStartingUp中我们创建了本例的主窗体,窗体中的文本筐在XAML中描述,文本筐被绑定到ContextMenuEvent事件,当用户在文本筐右击鼠标时触发该事件,创建一个上下文菜单对象(ContextMenu)。上下文菜单使用图形化设计器设计,通过选择背景色,前景色,边框,字体等等,你可以轻易的定制菜单(以及其他控件)的外观。这在Wind32编程中这种定制需要许多编程工作,而在.NET Framework中,托管代码封装了大部分的属性,用户可以控制的属性比较少。

菜单项使用MenuItem类来创建,而将它们绑定到事件处理器的方法几乎是和.NET中一样的:

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);

当一个菜单项被点击时,相应的事件处理器被执行,事件处理器的第一个参数被赋值为一个指向菜单项的引用:

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的owner:TextBox,这时要修改TextBox对象的内容就轻而易举了。

译后:

这是我翻译的第一篇技术资料。坦白的说,这不是一篇非常好的文章,应用模型的一个简单介绍,作者却罗嗦了这么长的篇幅,以至于翻完上半部分后我几度有放弃的想法。不过第一篇发表后读者的热情响应倒令我有些意外,于是我不得不对这篇文章重新评估,作为一篇介绍性的资料,作者其实已经尽职了的,虽然罗嗦但却浅鲜易懂,看着轻松的很,比起那些高深却晦涩的自然更受欢迎些了。在第二篇中,我有意的删减了一些内容,也是为大家节省点时间。对于Longhorn的开发,我想以后还会找一些好的文章翻出来给大家共享,也希望能得到大家支持和反馈。

Winsome

winsome_zhong@163.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有