所有的XAML均是一个WPF类,但是并不是所有的WPF类都可以用XAML描述。那些可以用XAML描述出来的元素大多数是用来表现用户界面的,这些元素都是由System.Windows.UIElement类派生出的。该类包含一些与可视化用户界面相关的属性,以提供给XAML元素使用。一个从System.Windows.UIElement派生的元素可以在页面上进行可视化的呈现、可以接受来自键盘和鼠标的输入、还可以可视化地调整大小和布局子元素的位置,以及触发事件。
并不是所有的XAML元素都派生自System.Windows.UIElement。例如LineBreak、TableColumn和Document等元素,都是派生自System.Windows.FrameworkContentElement类。通常该类中的元素是不能在页面上进行呈现出来的。
大部分的XAML元素按照其功能可以分为如下的5个部分:
·根元素
·控件元素
·面板元素
·图形和几何元素
·文档元素
根元素
根元素是用来作为包含所有用户界面元素的基本容器。一个XAML页面必须要有一个根元素,最常用的根元素有Page、Window、StackPanel、DockPanel、Canvas和Grid。我们可以在一个根元素包含一个或者多个XAML元素,这些包含在内的XAML元素称为该根元素的子元素(在你打开XAMLPad工具时,它会自动为你创建一个根元素-Page)。除了上述的几种根元素外,我们还可以从Page或Window中派生出一个新类,这样我们就可以创建自定义的根元素,并在XAML页面中使用。
根元素还必须引用适合的命名空间,就像以前的示例程序所显示的那样,我们在WPF程序中经常引用的命名空间为:
01 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/PResentation"
02 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
控件元素
控件元素处理和用户的交互。例如我们使用文本框控件输入数据、使用多选控件选择列表项或者执行其它的一些交互操作。这些控件元素按照其特性也可以分成5类
·简单控件 直接由System.Windows.Control派生而来,并且不包含Content、Items或Header等属性。这些控件主要有HorizontalScrollBar、VerticalScrollBar、Frame、TextBox和RichTextBox。
·内容控件 有Cotent属性,但是没有Items或Header属性。注重内容控件中只可以有一个XAML元素作为其包含的内容,但是所包含的XAML元素又可以包含多个元素,例如Panel元素。内容控件主要有Button、RepeatButton、Label、RadioButton、CheckBox、ListBoxItem、GroupItem、StatusBarItem、ToolTip、ScrollViewer和Window。
·项目控件 包含Items属性,但是没有Head和Content属性。项目控件通常用来展示多个选项供用户选择。这些控件主要有ListBox、ComboBox、Menu、ContextMenu、RadioButtonList, 和TabControl。
·标题项目控件 包含Head和Items属性,但是没有Content属性。Header属性用来为各个项目添加一个标题,而Items属性可以用来指定多个子元素。注重在标题项目控件中,Items属性是隐式声明的,也就是说我们并不直接使用Items属性指定各个子元素。下面通过下面的代码片断来查看标题项目控件(这里为MenuItem)的具体实现方式:
03 <MenuItem Header="First Menu Item">
04 <MenuItem Header="First Child Item" />
05 <MenuItem Header="Second Child Item" />
06 </MenuItem>
上述的示例中包含一个主MenuItem元素,并且使用Header属性为其指定说明信息。在<MenuItem>和</MenuItem>之间还包含了另外两个MenuItem元素,作为主MenuItem元素的子项目。
标题项目控件有如下两种,分别为MenuItem和ToolBar。
·标题内容控件 包含Header和Content属性,但是没有Items属性。如同内容控件一样,标题内容控件可以通过Content属性指定一个子元素。标题内容控件包括EXPander和TabItem。
Table 3-1. Attributes supported by control typ
控件类型
Content
Header
Items
Simple
N
N
N
Content
Y
N
N
Item
N
N
Y
Header item
N
Y
Y
Header content
Y
Y
N
面板元素
面板元素主要是用来处理页面的布局,并且可以作为容器来包含其它的元素,例如控件或其它的面板。一些从Panel派生的元素通常被用作为根元素,但是Panel的首要目的还是为XAML页面提供布局支持,并对页面上的各个元素进行合理的布置。尤其是一些非凡的面板元素,可以在设计时指定一个特定的布局方案。用来用户界面设计的面板元素包括DockPanel、StackPanel、Canvas、WrapPanel和Grid。
图形和几何元素
图形和几何元素通常是用来呈现二维矢量图形。图形元素派生自Shape类,我们使用这些元素我就可以直接创建相关的图形。在WPF中可以直接使用的图形包括Ellipse(椭圆)、Line(线)、Path、Polygon(多边形)、Polyline(折线)和Rectangle(矩形)。图形元素也是UIElement中的一种,这就意味着我们可以在Panel元素和其它的控件中使用这些图形控件。
几何元素,同样是用来呈现二维矢量图形,但是它比图形元素更具灵活性。我们可以使用几何元素来生成一些简单的二维矢量图形,例如圆或平面多边形,也可以用来构建一些复杂的矢量图形,例如贝塞尔曲线和弧形。注重,几何元素是无法进行自我呈现的,它必须依靠其它的元素才能绘制图形,例如Drawing和Path。因为几何元素只是创建图形的轮廓,并没有具体的呈现,所以我们还要使用那些在图形元素中经常使用的属性Fill(填充)、Stroke(画笔)和StrokeThicknessare(画笔浓度),来创建矢量图形的具体呈现方式。几何元素包括CombinedGeometry、LineGeometry, EllipseGeometry、GeometryGroup、PathGeometry、RectangleGeometry、PathSegment、ArcSegment, LineSegmen、BezierSegment、QuadraticBezierSegment、PolyQuadraticBezierSegment、PolyLineSegment, PolyBezierSegment、StartSegment和CloseSegment等。文档元素
文档元素是用来处理文档的呈现方式。文档一般分为两大类,流式布局和固定布局。FixedDocument元素就是用来设计那种所见即所得的固定布局。也就是说你在设计时,文档的格式是什么,在呈现时它的格式也是什么,没有任何的差异。
而用FlowDocument元素构建的流式布局文档在呈现时具备更好的灵活性,并且也提高了文档的可读性。流式布局文档的呈现效果是由多种因素决定的,例如屏幕和页面的大小、字体大小,以及用户的喜好所作的设置。流式布局文档是由一个或多个自Block或者Inline派生的元素组成的。Block、Figure、Floater、List、ListItem、Paragraph、Section、Table和TableCell等Block元素通常是用来组织和格式化文本块。而Inline元素则是用来格式化文本块中的文本信息,Inline元素主要包括Bold、accessKey、LineBreak、Hyperlink、Italic、Subscript、Superscript和Underline。
一些文档元素看起来是不是似曾相识,例如Paragraph、Table和Italic。是的,我们其它的一些用户界面标记语言中也会用到这些类似的格式化元素,例如Html中的<p>、<table>和<i>。虽然它们的实现机制都差不多,但是XAML中的文档元素包含了丰富的属性,这是相应的HTML副本所不具备的。
尽管XAML的核心语法和其他的标记语言(例如HTML)非常类似,但是XAML的用户界面元素在包含要呈现的内容时,所受到的限制是非常有限的,并不像HTML中那么严格。例如,我们在使用一个Button元素时并不一定就要使用文本作为提示信息,你还可以使用图片或者其它的由UIElement派生的元素作为提示信息。下面的这个示例就是一个在Button元素中,使用一个"红绿灯"式的三个圆作为提示信息。
07 <StackPanel xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
08 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
09 HorizontalAlignment="Center"
10 Margin="10">
11 <Button
12 Width="50"
13 Height="100">
14 <DockPanel>
15 <Ellipse Margin="5"
16 DockPanel.Dock="Top"
17 Stroke="Black"
18 Width="10"
19 Height="10"
20 Fill="Red" />
21 <Ellipse Margin="5"
22 DockPanel.Dock="Top"
23 Stroke="Black"
24 Width="10"
25 Height="10"
26 Fill="Yellow" />
27 <Ellipse Margin="5"
28 DockPanel.Dock="Top"
29 Stroke="Black"
30 Width="10"
31 Height="10"
32 Fill="Green" />
33 </DockPanel>
34 </Button>
35 </StackPanel>
QQread.com
推出各大专业服务器评测 linux服务器的安全性能
SUN服务器
HP服务器
DELL服务器
IBM服务器
联想服务器
浪潮服务器
曙光服务器
同方服务器
华硕服务器
宝德服务器
属性
在本文曾多次提过XAML元素的属性是和WPF类中的属性对应的,例如XAML中的Button元素存在Width属性,该属性是和System.Windows.Button类中的Width属性对应的。为了说明XAML和WPF类的相互关系,我们分别在如下的两个程序清单中使用XAML和C#来声明一个Button元素实例:
36 <Button
37 Width="100"
38 Name="myButton"
39 Height="20"
40 Content="This is my button" />
相应的C#代码实现:
41 Button myButton;
42 myButton.Width=100;
43 myButton.Height=20;
44 myButton.Content = "This is my button";
就如同XAML中的Button元素名称和Button类的名称相同一样,Button元素的各个属性也和Button类中的属性名称一一对应(Name= Name,Height=Height,依此类推)。
在上述代码示例中,Name和Content属性的类型都是String,因为XML本身就是一种基于文本的格式,所以其属性值用文本来描述是合乎情理的。那么作为XML的一种衍生类型,XAML其属性是否还有其它类型呢?我们在下面的示例代码使用了不同的属性类型:
45 <Rectangle
46 Width="200"
47 Height="100"
48 Stroke="Red"
49 Fill="Yellow" />
在上述的Rectangle元素中没有一个属性是String类型的,Width和Height都是Double类型的,而Stroke和Fill是Brush类型的。为了支持各自不同的属性类型,XAML需要使用.NET中的类型转换系统(TypeConverter)。也就是在XAML中的所有属性值都是用文本字符串来描述的,但是类型转换系统会在某一特定的阶段将这些文本字符串和属性本身的类型映射起来。例如在上述的示例中,LengthConverter类型转换器会自动将Width和Height对应的"200"和"100"文本字符串转换为双精度类型的200和100(WPF之所以知道使用Double类型是因为在FrameworkElement类中的WidthProperty和HeightProperty字段被标记了一个TypeConverterAttribute,这样就可以知道在类型转换时使用何种类型转换器)。由于Stroke和Fill这两个属性并没有标记一个TypeConverterAttribute,但是它们都是属性Brush类型的,而Brush类型又标记一个TypeConverterAttribute来指定其类型转换器为BrushConverter,所以BrushConverter会自动将其文本字符串类型的属性值转换为Brush类型。
尽管WPF中的类型转换系统是非常有用的,但是在某些情况下它仍然存在着一些不足。例如某个属性值不存在适合的类型转换器进行从文本到实际类型的转换,或者是一个描述属性值的文本字符串过于复杂,以致我们不得不作大量的工作才可以实现类型的转换。现在请你考虑一个问题,我们要实现上述的给矩形填充一种颜色是非常轻易的,但是假如我们要给一个矩形填充多种颜色该怎么实现呢(具体的效果见3-3)?我们不可以像上面那样直接使用Fill="Yellow Red…"这样的方式去为矩形设置不同的颜色,也就是说BrushConverter类型转换器是无法直接转换这种包含多个颜色描述文本的字符串的。为了讲解上述类型转换系统的缺点,这里引入了一个新的概念,那就是从属属性。
图3-3 带渐变效果的Button元素
这里先使用一个简单的实例来说明下什么是从属属性,从属属性就是一种"属性-元素"的语法,使用这种语法来设置一个属性时,你可以使用一种嵌套方式的元素替代原本要设置的属性。这个嵌套方式的元素其格式为"父元素.属性名",这里的父元素就是将要设置属性的元素,而属性名就是对应的在元素中要设置的属性。这里说的可能让你有点糊涂,没关系,现在我们看看下面的程序清单:
01 <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
02 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
03 <Button Width="200" Height="100">
04 <Button.Background>
05 <SolidColorBrush Color="Blue" />
06 </Button.Background>
07 Click me
08 </Button>
09 </Page>
这是对应的C#实现代码:
01 Button BTn = new Button( );
02 SolidColorBrush brush = new SolidColorBrush( );
03 brush.Color = Colors.Blue;
04 btn.Background = brush;
05 btn.AddText("Click me");
我们要为Button预算设置其背景颜色为蓝色。在上面的示例中我们使用了从属属性"父元素.属性名"类型的语法,其中第4行的<Button.Background>就是一个从属属性,它以元素的形式存在,但是其实质上却是一个属性。
上面仅仅是为了让你了解从属属性的用法和实现方式,假如只是为了实现上述的效果,那么下面的程序清单完全就可以实现,你只需将Background设置为"Blue"就行了完全没有必要大费周章地使用从属属性。尽管使用"父元素.属性名"这样格式的从属属性去设置一个背景颜色显得很复杂,但是这种版本的实现可以清楚地看到你在这所创建的是何种类型的brush。
01 <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
02 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
03 <Button
04 Width="200"
05 Height="100"
06 Background="Blue">
07 </Button>
08 </Page>
假如使用从属属性只是为了了解底层的类型转换实现机制的话,那么我们根本就没有理由去使用这些冗长的语法实现。从属属性之所以重要是因为在某些情况下我们需要在一个属性中实现非常复杂的定义,就如同我们上述提及的要在一个矩形中使用多种颜色作背景。其代码如下:
01 <Button VerticalAlignment="Center" HorizontalAlignment="Center">
02 <Button.Background>
03 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
04 <LinearGradientBrush.GradientStops>
05 <GradientStop Offset="0" Color="Yellow" />
06 <GradientStop Offset="0.35" Color="Red" />
07 <GradientStop Offset="1" Color="Green" />
08 </LinearGradientBrush.GradientStops>
09 </LinearGradientBrush>
10 </Button.Background>
11 Click me
12 </Button>
这是使用C#实现的对应版本
01 Button b = new Button( );
02 b.VerticalAlignment = VerticalAlignment.Center;
03 b.HorizontalAlignment = HorizontalAlignment.Center;
04 LinearGradientBrush brush = new LinearGradientBrush( );
05 brush.StartPoint = new Point(0,0);
06 brush.EndPoint = new Point(0,1);
07 GradientStop gs = new GradientStop( );
08 gs.Offset = 0;
09 gs.Color = Color.FromRgb(0x80, 0, 0);
10 brush.GradientStops.AddChild(gs);
11 gs = new GradientStop( );
12 gs.Offset = 0.35;
13 gs.Color = Colors.Red;
14 brush.GradientStops.AddChild(gs);
15 gs = new GradientStop( );
16 gs.Offset = 0.35;
17 gs.Color = Color.FromRgb(0x50, 0, 0);
18 brush.GradientStops.AddChild(gs);
19 b.Background = brush;
20 b.AddText("Click me");