WPF入門之XAML初窺

1. 什麼是XAML?

XAML是一種相對簡單、通用的聲明式變成語言,它適合於構建和初始化.NET對象。它由一些規則和關鍵字構成,但是它自己沒有任何有意義的元素。在沒有WPF/WF框架的基礎上討論XAML就象在沒有.NET Framework的基礎上討論C#一樣是沒有任何意義的,因爲它本身並不能提供任何有意義的元素,需要由WPF/WF框架或者說.NET XAML編譯器和WPF應用框架來承載、理解XAML的表達意義。由於XAML的通用性,實際上你可以把它應用於任何.NET技術。然而,是否在使用WPF時使用XAML是可選的,每一個XAML能做的事情完全可以由任何一種你喜歡的.NET語言來實現,但是反過來是不行的。在後邊的解釋中你會看到,實際上針對XAML的解釋,XAML編譯器是把XAML語句與.NET對象/類型聯繫在一起的,將XAML納入和.NET類型相同的模型中控制是他們爲什麼能夠互相兼容的重要原因。

例如如下的XAML片段和.NET C#語句所表達的結果是相同的:

XAML: <Button xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation Content="OK" />

C#:     System.Windows.Controls.Button btnOk = new System.Windows.Controls.Button();

          b.Content = "OK";

2. XAML元素及特性

2.1 XAML命名空間

XAML文件的跟對象元素必須至少有一個XML命名空間,用於驗證自己和其子元素。你可以在根元素或子元素上聲明額外的XML命名空間來標識你的自定義元素,但每個命名空間下的標識符都必須有一個唯一的前綴。我們把http://schemas.microsoft.com/winfx/2006/xaml/presentation作爲默認(主要)的命名空間,我們在使用大多數控件時都使用此主命名空間,因爲WPF通過硬編碼的方式將此命名空間與.NET的命名空間進行了映射。而對於次命名空間,我們通常需要添加前綴來表示其命名空間在以下範圍內被引用,中就像C#中的using System;一樣,聲明瞭一個可以引用的命名空間。以下代碼片段演示瞭如何使用主命名空間和次命名空間:

<UserControl x:Class="MediaPlayer.Page"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="450" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock FontSize="12" FontWeight="Bold" HorizontalAlignment="Center">Vedio Player</TextBlock>
    </Grid>
</UserControl>

2.2 屬性元素(Property Element)

屬性元素本質上是爲了增加在元素中包含子元素的一種方式。它是XAML提供的用來替代更加詳細的語法來設置屬性值的方法。例如:

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

    <Button.Content>

        </Rectangle Height="40" Width="40" Fill="Black" />

    </Button.Content>

</Button>

Content屬性現在被設置爲一個XML元素而不是XML屬性,Button.Content中的句點用來區分對象元素與屬性元素。屬性元素總會以“類型名.屬性名”的形式出現幷包含在“類型名”對象元素中。說白了,屬性元素是爲了擴展某類型的屬性而存在的。

2.3 類型轉換器(Type Converter)

在XAML中實際上我們都是以String的類型來賦予各種屬性值的,但在對於.NET這樣的有類型庫來講,不是所有的屬性值都是爲String的,比如對於Button的Background屬性,在C#中我們需要這樣來寫:

System.Windows.Controls.Button b = new System.Windows.Controls.Button();

b.Content = “OK”;

b.Background = System.Windows.Media.Brushes.White;

這段C#代碼等同於下邊的XAML代碼片段:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK">

   <Button.Background>

White

</Button.Background>

</Button>

可以很容易的發現,在C#中Button的Background屬性對應的類型爲System.Windows.Media.Brushes,而在XAML中由於無法具有強類型表現方式(當然它是通過另一種替代方式來表現的,只是表面上都是String)這裏選擇了用White這個字符串來表示我們想用White顏色來作爲背景顏色。因爲這個代碼片段是等同的,我們可以自然的將White字符串認爲等同於System.Windows.Media.Brushes.White。而這個映射就是通過類型轉換器來實現的。這裏就通過BrushConverter和ColorConverter一起將White設置爲Button的Background(因爲Background實際上是Brush類型的)-而這些轉換器都是派生自TypeConverter的類。PS:這裏另一個參考就是我們在寫ASP.NET的自定義控件時裏邊都會有定義一些Converter,但他們是不一樣的。

其實以上的XAML代碼是簡化的寫法,更好的理解它我們可以寫爲下邊這種方式(等價的):

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK">

   <Button.Background>

<SolidColorBrush Color=”White” />

</Button.Background>

</Button>

而對應的C#代碼,爲了更好的理解類型轉換器,我們改寫爲下邊這種方式:

System.Windows.Controls.Button b = new System.Windows.Controls.Button();

b.Content = “OK”;

b.Background = (Brush)System.ComponentModel.TypeDescriptor.GetConverter(typeof(Brush)).ConvertFromInvariantString(“White”);

2.4 擴展標記

擴展標記就像類型轉換器一樣是用來擴展XAML的表達能力的,他們都可以在運行時計算字符串特性的值並生成合適的基於字符串的對象。但與類型轉換器不同的是,標記擴展是通過XAML的顯式的、一致的語法調用的,因此這是比較好的擴展XAML的方法。一般來講我們更多的把擴展標記應用於Resource, Binding等。如下邊的例子我們通常會用來標記當前元素/對象是使用的樣式(Resource):

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

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

Title="Simple Window">

<Window.Resources>

<SolidColorBrush x:Key="backgroundBrush">Yellow</SolidColorBrush>

<SolidColorBrush x:Key="borderBrush">Red</SolidColorBrush>

</Window.Resources>

<DockPanel>

<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal"

HorizontalAlignment="Center">

<Button Background="{StaticResource backgroundBrush}"

BorderBrush="{StaticResource borderBrush}" Margin="5">

<Image Height="21" Source="zoom.gif"/>

</Button>

</StackPanel>

</DockPanel>

</Window >

2.5 集合項

XAML允許將項添加到支持索引的兩種類型的集合中:List和Dictionary.

List: 實現了System.Collections.IList接口的集合,它的Items屬性是實現了IList的ItemCollection類型;

Dictionary: 實現了System.Collections.IDictionary接口的集合,能夠支持在過程式代碼中添加、移除和枚舉鍵/值對。

下邊兩個例子展示了在XAML中如何應用集合項。注意:由於Content屬性實際上相當於在.NET對象中的默認屬性(例如在自定義控件中的默認屬性),所以可以將內容屬性的值作爲此對象的直接子元素而不用Content屬性元素來標明,以此來簡化XAML的複雜度。

<ListBox xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation>

<ListBox.Items> <!—直接將子元素作爲內容屬性—>

<ListBoxItem Content=”Item 1” /><!—等同於<ListBoxItem>Item 1</ListBoxItem>-->

<ListBoxItem Content=”Item 2” />

</ListBox.Items>

</ListBox>

3. 編譯XAML

XAML編譯 通常包括三項事情:將一個XAML文件轉換爲一種特殊的二進制格式(BAML:Binary Application Markup Language);將轉換好的二進制資源嵌入到正在被創建的程序集中;然後執行鏈接操作將XAML和過程式代碼自動連接起來。

每個XAML都會在編譯過程中產生過程式代碼,這是在編譯過程中動態生成的,但這些過程代碼僅僅是“粘合代碼”Glue Code,類似於在運行時加載和解析鬆散XAML文件時所需要的代碼(和普通的Win Form自動生成的代碼用途類似),你可以在.g.cs(.g.vb)文件中找到這些代碼。

同樣你可以在XAML中混合使用過程代碼(Code inside),當XAML編譯後X:code元素中的部分將會放到部分類.g.cs文件中。

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

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

<Button Click=”button_Click”>OK</Button>

<x:Code><![CDATA[

Void button_Click(object sender, RouteEventArgs e)

{

this.Close();

}

]]></x:Code>

</Window>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章