XAML 概述二

經過上一節咱們已經對XAML有了必定的瞭解,這一節咱們來系統的學習一下XAML。curl

 

一. 簡單屬性與類型轉換器,屬性元素:ide

咱們已經知道 XAML是一種聲明性的語言,而且XAML解析器會爲每一個標籤建立一個與之對應的對象。光有對象是沒有任何意義的,須要對屬性之類的賦值纔有使用意義。因此就要求XAML爲對象屬性賦值。XAML中爲對象屬性賦值共有2種語法:函數

 · 使用字符串進行簡單賦值學習

 · 使用屬性元素進行復雜賦值ui

<TextBox VerticalAlignment="Stretch" HorizontalAlignment="Stretch" FontFamily="Verdana" FontSize="14" Foreground="Gray">XAML</TextBox>

爲了使上面的設置起做用,System.Windows.Controls.TextBox類必須提供上面面這些屬性。url

上面的設置中,有2個屬性爲枚舉類型(VerticalAlignment,HorizontalAlignment),一個FontFamily類型,一個double類型(FontSize)和一個SolidColorBrush類型(Foreground)。在XAML中,Attribute的值老是一個字符串的值。爲了使之能正常工做,XAML解析器悄悄的執行了類型轉換:spa

1.首先檢查屬性聲明,查找該屬性是否使用了TypeConverter特性;若是使用了就能進行類型轉換。code

2.若是屬性聲明中沒有使用TypeConverter特性,就查找數據類型的類的聲明;若是使用了就能進行類型轉換。xml

若是屬性和類中都沒有聲明,XAML解析器就會生成一個錯誤。對象

     [Category("Appearance"), Localizability(LocalizationCategory.None), TypeConverter(typeof(FontSizeConverter)), Bindable(true)]
        public double FontSize
        {
            get
            {
                return (double)base.GetValue(FontSizeProperty);
            }
            set
            {
                base.SetValue(FontSizeProperty, value);
            }
        }

        [Category("Appearance"), Bindable(true)]
        public Brush Foreground
        {
            get
            {
                return (Brush)base.GetValue(ForegroundProperty);
            }
            set
            {
                base.SetValue(ForegroundProperty, value);
            }
        }

咱們查看源代碼就能夠看到,FontSize屬性聲明瞭TypeConverter特性,可是Brush沒有。咱們再查看Brush類聲明的源代碼,就會發現有一個TypeConverter(typeof(BrushConverter))特性。其中BrushConverter,FontSizeConverter都是實現了TypeConverter的類型轉換類。

 

雖然類型轉換器很方便,可是不能解決全部的問題。有些屬性是完備的對象,這些對象有着本身的一系列屬性。若是繼續使用類型轉換器的話,語法會很複雜,也有可能出錯。幸虧XAML提供了一種更好的選擇:屬性元素。其語法爲:

<ClassName>
     <ClassName.AttributeName></ClassName.AttributeName>
</ClassName>

重要的就是中間的那個點(.) 

 

二.標記擴展(Markup Extensions)

仔細觀察XAML中爲對象屬性賦值的語法,大多數都是爲屬性生成一個新對象。但有的時候須要把同一個對象賦值給兩個對象的屬性,還有時候須要給對象的屬性賦null值,或者賦值爲一個靜態對象等。這個時候就須要標記擴展了。

有2種方式能夠設置標記擴展:

 · 當用於提供特性值時,語法就是左右大括號({ 和 })。 而後,由緊跟在左大括號後面的字符串標記來標識標記擴展的類型。

 · 當用在屬性元素語法中時,標記擴展在外觀上與其餘任何用於提供屬性元素值的元素相同,即:一個將標記擴展類做爲一個元素引用並以尖括號 (<>) 括起的 XAML 元素聲明。

 

儘管標記擴展的語法簡單方便,可是不是全部的對象都能使用標記擴展的語法來書寫。只有直接或間接實現了System.Windows.Markup.MarkupExtension 的類才能使用標記擴展。

標記擴展並很少,它們是:

 · XAML定義的標記擴展:x:Type 、x:Static、x:Null、x:Array (這幾個後面介紹x命名空間的時候會介紹到它們的用法,它們並不是是 XAML 的 WPF 實現所特有的,而是語言形式的 XAML 的內部函數或功能實現。)

 

 · 特定於WPF的標記擴展:StaticResource、DynamicResource、Binding、RelativeSource、TemplateBinding、ColorConvertedBitmap、ComponentResourceKey、ThemeDictionary (後面的章節中會介紹它們中部分的用法)

 

最後要注意一下幾點:

· 標記擴展是能夠嵌套的,逗號表示各個標記的分隔符,例如:

<TextBox Text="{Binding Source={StaticResource Person},Path = Name}"></TextBox>

· 標記擴展有一些簡寫語法,如{Binding Name,...}與{Binding Path = Name,...}是等價的。兩種寫法中,前者稱爲固定位置參數(Positional Parameter),後者稱爲具名參數(Named Parameters)。固定位置參數實際就是構造函數的參數,其位置由構造函數參數列表決定。若是是具名參數,則會首先爲標記擴展調用默認構造函數;以後,每一個「名稱=值」對都會被解釋爲標記擴展上存在的屬性名稱以及賦給該屬性的值。

· 標記擴展類幾乎以單詞Extension爲後綴(Binding除外),在XAML中使用的時候能夠全寫StaticResourceExtension,也能夠簡寫StaticResource。其實這點只用知道就行,咱們在用Visaul Studio的時候,智能感知就已經幫咱們用簡寫的方式了。

   

三.附加屬性

附加屬性是由 XAML 定義的概念。附加屬性是能夠用於多個控件但在一個類中定義的屬性。一般的語法爲:AttachedPropertyProvider.PropertyName。

<Grid>
     <TextBox Grid.Row="0">XAML</TextBox>
</Grid>

後面有章節會專門講到附加屬性,到時候再專門講它。

 

四.嵌套元素

正如咱們看到,XAML文檔被排列成一個巨大的嵌套元素的樹。XAML中有3種機制能夠決定如何處理嵌套元素:

· 若是父元素實現了IList接口,解析器就會調用IList.Add()方法,而且爲該方法傳入子元素做爲參數。

· 若是父元素實現了IDictionary接口,解析器就會調用IDictionary.Add()方法,併爲該方法傳入子元素做爲參數。當使用字典集合的時候,必須使用x:Key特性以便爲每一個條目指定鍵名。

<TextBox>
     <TextBox.Background>
          <LinearGradientBrush>
                <GradientStopCollection>
                     <GradientStop Offset="0" Color="Red"></GradientStop>
                     <GradientStop Offset="0.5" Color="LavenderBlush"></GradientStop>
                     <GradientStop Offset="1" Color="WhiteSmoke"></GradientStop>
                </GradientStopCollection>
          </LinearGradientBrush>
     </TextBox.Background>
</TextBox>

咱們查看GradientStopCollection類的源碼,就能夠發現它實現了IList接口,因此解析器把每一個GradientStop以IList.Add()的方式添加到集合中。

· 若是父元素使用了ContentProperty特性,解析器就會使用子元素設置其對應的屬性。

列如咱們的查看Grid的源代碼,雖然該類沒有使用ContentProperty特性,可是Grid的父類Panel類使用了該特性ContentProperty("Children")。這代表應該使用任何嵌套元素來設置Children屬性。XAML解析器會根據是不是一個集合屬性(集合屬性是否實現了IList接口和IDictionary接口),以不一樣的方式來處理內容屬性。由於Panel.Children返回的是一個UIElementCollection對象,而且該對象實現了IList接口,因此解析器使用IList.Add()方法把嵌套的元素添加到集合中。

var grid = new Grid();
var textBox = new TextBox();
grid.Children.Add(textBox);

嵌套的內容不徹底就是一個集合,咱們查看TextBox,發現它ContentProperty("Text")指向的是一個Text屬性,而且該屬性返回的是一個string類型。因此TextBox的嵌套元素只能爲一個字符串。

還一個Button類,咱們知道它的直接基類ButtonBase,並無發現ContentProperty特性;而後再往上找ContentControl這個基類,就發現了ContentProperty("Content")指向的是Content屬性;查找該屬性,就會發現它返回的是一個object類型。全部能夠在Button中嵌套任何元素。

 

五.事件

到目前爲止,介紹的全部Attribute都被映射爲Property。而後,Attribute也能夠關聯事件處理程序。若是使用Visual Studio的話,就能夠自動的幫咱們完成事件和後臺代碼的建立與關聯。

也可使用Code元素,直接在XAML文檔中嵌入代碼(如事件處理程序)。

<StackPanel>
     <Button Content="Button" Click="button_Click"></Button>
</StackPanel>
    
<x:Code>
     <![CDATA[
         private void button_Click(object sender,RoutedEventArgs e)
         {
             MessageBox.Show("Bye!Code-Behind!");
         }
     ]]>
</x:Code>

不過最好不要使用這一作法,WPF中並不須要使用這一技術,不值得推薦。

 

六.導入程序集和引用其中的命名空間

這個使用很簡單,只須要把須要引用的dll添加到程序引用。而後再使用xmlns:Prefix="clr-namespace:NameSpace;assembly=AssemblyName"語法就行。

Prefix:命名空間前綴。

NameSpace:徹底限定的.NET命名空間名稱

AssemblyName:聲明類型的程序集,沒有.dll擴展名

 

七.註釋與特殊符號

XAML的註釋語法繼承自XML。語法爲:<!--須要註釋的內容-->

不過有幾點須要注意:

· 註釋只能出如今標籤的內容區域,也就是說只能出如今開始和結束標籤之間

· 註釋不能用於標籤的Attribute

· 註釋不能嵌套

 

特殊的符號:

特殊字符 字符實體
< &lt;
> &gt;
& &amp;
" &quot;

 

 

 

 

 

 

接下來的一節,咱們會了認識一下x命名空間下的具體內容。

相關文章
相關標籤/搜索