代码改变世界

第二章XAML

2012-07-21 13:10  桂仙人  阅读(304)  评论(0)    收藏  举报

1.XAML 基础
一旦理解了一些原则XAML就变得非常简单,理解起XAML就非常简单
1.1在XAML文档中每个元素都隐身为.NET类的实例。元素的名称也完全对应一个类名,例如:<button></button>创建一个button对象。
1.2 和XML文档一样,可以吧一个元素嵌套到另外一个元素。

1.3 可以通过特性为每个类设置属性(property)。

 

<Window x:Class="WpfApplication1.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="MainWindow" Height="350" Width="525">

    <Grid>

       

    </Grid>

</Window>                                               

 

这个文档中包含两个元素-顶级元的Window元素,以及一个Grid元素,window元素代表整个窗口,在Grid元素中可以放置所有控件,尽管可以任何顶级元素,

WPF中使用以下几个元素作为顶级元素

Window 元素

Page 元素

Application元素(定义应用程序资源和启动设置)

XAML中只能有一个顶级元素。

 

2.XAML命名空间

 

显然只有类名是不够的,XAML还要知道类是在哪个命名空间下面的,

xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation 是WPF的核心命名空间。它包含了所有的WPF类,包含用于构建用户界面的类。

xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml是XAML的命名空间。

 

在这里注意的是XAML的命名空间与.NET里面的命名空间不是一一对应的,

如果一一对应会增大XAML文档的复杂程度。

 

3.后台代码类

  /// <summary>

    /// MainWindow.xaml 的Ì?交?互£¤逻?辑-

    /// </summary>

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

        }

    }

当编译应用程序时,定义的用户界面的XAML被转化成CLR类的声明,这些类型声明与后台的逻辑代码融合到一起,形成一个单独的单元。

 

InitializeComponent()方法在WPF中扮演者重要的角色,如果添加另外一个构造函数的时候要确保调用InitializeComponent()该方法

 

/// </summary>

        [System.Diagnostics.DebuggerNonUserCodeAttribute()]

        public void InitializeComponent() {

            if (_contentLoaded) {

                return;

            }

            _contentLoaded = true;

            System.Uri resourceLocater = new System.Uri("/WpfApplication1;component/mainwindow.xaml", System.UriKind.Relative);

           

            #line 1 "..\..\..\MainWindow.xaml"

            System.Windows.Application. LoadComponent (this, resourceLocater);

           

            #line default

            #line hidden

        }

所有的InitializeComponent()方法都调用了Application中得LoadComponent()方法,当解析BAML(XAML编译之后)时,LoadComponent()方法创建每个控件的对象,设置器属性。并关联所有的事件处理程序。

 

 

4.XAML中得属性和事件

 

4.1简单属性和类型转化器

       <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontSize="24" FontFamily="BatangChe"></Button>

在上面的代码中有HorizontalAlignment,VerticalAlignment是枚举类型,FontFamily是字符串类型,一个整形FontSize 。

为了跨越字符创和非字符创之间的鸿沟,XAML执行需要转化,类型转化器从.NET1.0就存在.NET架构的一个基本组成部分。

实际上,被转化的类型在这一个过程中扮演中重要的角色-类型提供了实用的方法,这些类型可以将一些特定的类型转化成.NET类型。

XAML通过下面两个步骤来查找类型转化器:

1),检查属性声明,查找TypeConverter特性(如果提供TypeConverter特性,该特性将指定他修饰的类可以执行什么样的转换)。

2)如果没有找到TypeConvert特性,XAML解析器将检查对应数据类型的类的声明。

4.2扩展属性

对于大多数属性,XAML可以工作的非常好,但是有些情况下,不可能硬编码属性值。例如:

1).可能希望为一个已经存在的对象设置属性值.

2)可能希望通过将一个属性绑定到另一个控件来动态的设置属性值。

扩展标记可用于嵌套的标签中,在XAML特性中通常用{}包围起来,例如:

下面掩饰了如何使用StaticExtension标记扩展,它可以使用StaticExtension扩展标记,他可以引用另外一个类中的静态属性

<button Foreground={x:Static SystemColors.ActiveCaptionBrush}”>

 

扩展标记的语法为{标记扩展类 参数}

通常可以省略Extension

X:前缀指示在一个XAML名称空间中查找StaticExtension类

所有的标记扩展都实现了System.Windows.Markup.MarkupExtension基类

MarkupExtension基类非常简单他只提供了一个ProvideValue()方法,该方法获取所希望的数值,当XAML遇到上面语句的时候,他创建了一个StaticExtension类的实例,并将SystemColors.ActiveCaptionBrush作为构造函数的参数,然后调用ProvideValue()方法获取SystemColors.ActiveCaptionBrush静态属性返回的对象,

最后使用返回的对象设置button的Foreground属性。

 

4.3复杂属性

XAML提供了一种属性元素语法:Parent.PropertyName形式的子元素,例如:

Grid控件有一个Background属性,该属性提供了一个绘制背景的画刷,如下所示:

<Grid>

        <Grid.Background>

           

        </Grid.Background>

    </Grid>

关键的细节在元素使用句点。该句点将该元素和其他类型的元素需分开来。

在嵌套元素中,可以添加其他标签来实例化特定的类。

<Grid>

        <Grid.Background>

            <LinearGradientBrush></LinearGradientBrush>

        </Grid.Background>

    </Grid>

可以通过<LinearGradientBrush></LinearGradientBrush>的元素可以创建对象。这只是创建了一个简单的对象,如果需要为指定渐变的颜色。需要使用GradientStop对象的集合填充LinearGradientBrush,.GradientStops属性可以完成这一工作。

<Grid>

        <Grid.Background>

            <LinearGradientBrush>

                <LinearGradientBrush.GradientStops>

                </LinearGradientBrush.GradientStops>

            </LinearGradientBrush>

        </Grid.Background>

    </Grid>

最后使用GradientStop对象填充GradientStops集合。

  <Grid>

        <Grid.Background>

            <LinearGradientBrush>

                <LinearGradientBrush.GradientStops>

                    <GradientStop Offset="0.00" Color="Red"/>

                    <GradientStop Offset="0.50" Color="Indigo"/>

                    <GradientStop Offset="1.00" Color="Violet"/>

                </LinearGradientBrush.GradientStops>

            </LinearGradientBrush>

        </Grid.Background>

    </Grid>

 

4.4附加属性

每个控件都有自己固有的一些属性,当在包容器中放置一个控件时,根据包容器的类型他会获取额外的一些特征,这些附加的细节使用附加属性设置。

<textbox grid.row=”0”></textbox>附加属性不完全是属性,他们实际上被转化成方法调用,例如:定义一个Grid类,并且属性是Row,所以解析器调用Grid.SetRow()

F方法,当调用SetRow()方法的时候解析器传两个参数SetRow(控件名称,0);

 

4.5嵌套元素

XAML文档被排成一颗巨大的嵌套元素树。例如,在上面一个Window元素包含一个Grid元素,Grid元素有包含了TextBox元素和Button元素。

XAML元素让元素决定如何处理嵌套的元素,这种交互使用下面三种中得一种进行中转:

  1. 如果父元素实现了Ilist接口,解析器就会调用Ilist.Add()方法,并且为该方法传入子元素作为参数。
  2. 如果父元素实现了Idictionary接口,解析器就会调用该接口的Add()方法,并且为该方法传递元素做为参数。

3. 如果父元素使用了ConentProperty属性进行修饰,该解析器使用对应的属性。

 

在上面的GradientStops属性中,该属性返回一个GradientStopCollection对象,并且该对象实现了Ilist接口。

 

嵌套内容并不总是全部是一个集合,例如:

<Grid>

。。。

<textbox></textbox>

<buton></button>

。。。。。

</Grid>

这些嵌套并不是复杂属性,因为他们没有包含句点,而且Grid也不是一个集合。Grid支持ContentProperty特性,该特性被应用与Panel,而grid类又继承与Panel类

[ConetntPropertyAttribute(“Childeren”)]

Public abstract class Panel

上面Panel类的特性指示任何嵌套元素应当被设置为Children属性。Panel.Childeren属性返回一个UIElementCollection对象,并且该对象实现了Ilist接口。

 

ContentProperty特性在WPF中经常使用特性,不仅包含在Grid控件中,而且那些可视化集合的控件ListBox,TreeView控件都用了该特性,而且那些包含了单个的内容控件

TextBox应用于ContentProperty特性标示了TextBox.Text属性,Button类使用了ContentProperty特性标示了Button.Content属性。

 

 

5.事件

 

用于关联事件处理程序的语法为:事件名=”事件处理程序方法名”

 

6.使用其他命名控件中得类型

 

Xmlns:prefix=”clr-namespace:Namespace;assembly=AssemblyName”

 

Prefix是指XAML标记中用于指示希望命名控件的前缀。

Namespace是.NET命名控件的完整限定。

AssemblyName是声明类型的程序集,没有扩展的.dll。