WPF高級教程(三)XAML

語言簡介

  • XAML(Extensible Application Markup Language) 是用來寫界面的
  • XAML是大小寫敏感的
  • WPF是前後端分離的,前端用XAML實現,後端用C#寫(注意能用XAML寫的都能用C#實現,但是用XAML更加直觀,我們在本篇教程裏,一般只說明使用XAML的實現,如果大家需要在後臺更改界面,可以自行搜索XAML對應的C#實現)

命名空間

格式

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  • http:// 並不是一個網址,而是十幾個命名空間的集合,這樣做,既保證了這個Uri不會於用戶自定義的命名空間重複(因爲schemas.microsoft.com是微軟所有的)也降低了文檔的複雜程度,不用寫十幾個命名空間了。
  • xmlns:x 表示這個命名空間的別名是x,在使用的過程中可以通過x:Name使用這個命名空間下的對象
  • presentation 是WPF核心命名空間,沒有前綴,默認(像Button這種)都在這個命名空間之內
  • xaml 是XAML的命名空間

不同項目中的命名空間的引用

xmlns:Prefix="clr-namespace:Namespace;assembly=AssemblyName"

注意AssemblyName是程序集名稱,只要在該項目中引用過即可使用。如果就在本程序集中,則可以忽略這個選項。

// 把當前項目程序集設置爲local
xmlns:local="clr-namespace:MyNamespace"

類名 部分類

x:Class="Novc.ViPlex.Express.View.AboutView"

這個聲明使得XAML生成了一個部分類,與後臺的部分類一起構成了完整的窗體類定義

XAML加載

InitializeComponent方法

  • 這個方法的作用是加載XAML並且構建用戶界面
  • 當自定義構造函數的時候必須寫上這個方法

事件和屬性

XAML加載的順序是先設置Name屬性,再給元素掛載事件,最後加載屬性。所以,如果監聽了某個屬性的變化的事件,在第一次設置該屬性的時候(加載屬性的時候),事件都會觸發一次。

屬性的類型轉換器(TypeConverter)

在XAML中,屬性的設置全部是字符串類型的,但是屬性的類型卻是多種多樣的,比如Image的Source是一個BitmapImage類型,VerticalAlignment是枚舉類型。爲了解決這個問題,.NET引入了類型轉換器的概念

類型轉換器存在於

  • 需要設置的屬性中,比如 Background 屬性
  • 屬性設置的值中,比如Background需要使用一個Brush對象,XAML也會檢測Brush中是否有類型轉換器

屬性的設置

  1. 直接設置屬性(使用類型轉換器)

    HorizontalAlignment="Left"
    
  2. 設置複雜屬性
    屬性元素語法,語法規則爲Parent.Property,用於設置一個複雜的,對象類型的屬性值。

    <Grid HorizontalAlignment="Left" Height="100" Margin="196.617,195.39,0,0" VerticalAlignment="Top" Width="118.795">
        <Grid.Background>
            <LinearGradientBrush>
                <GradientStop Offset="0.00" Color="Red"></GradientStop>
                <GradientStop Offset="0.50" Color="Indigo"></GradientStop>
                <GradientStop Offset="1.00" Color="Violet"></GradientStop>
            </LinearGradientBrush>
        </Grid.Background>
    </Grid>
    
  3. 使用標記擴展設置屬性(不太常用,知道即可)

    當我們要給一個屬性設置爲一個已經存在的屬性的時候使用,例如,A類中有一個靜態的Brush,B.xaml中需要使用A中的Brush,需要注意的是,A中的Brush必須是靜態的,即通過類名就可以訪問。

    <Button Foreground="{x:Static SystemColors.ActiveCaptionBrush}"/>
    

    注意上面的語法,Static是StaticExtension的簡寫,即靜態擴展,在後臺中這樣寫

    cmdAnswer.Foreground = SystemColors.ActiveCaptionBrush;
    

    作爲嵌套屬性這樣寫,注意需要使用Member:

    <Button.Foreground>
        <x:Static Member="SystemColors.ActiveCaptionBrush"/>
    </Button.Foreground>
    
  4. 設置附加屬性

    簡單說,附加屬性就是一些屬性只有在某種特性情況下才能被設置,比如控件在Grid中的時候才能設置Grid.Row。

    這裏我們多分析兩句,想必設置Grid.Row人人都會,但是爲什麼它叫附加屬性呢?因爲TextBox中本來沒有這個屬性,Background,TextAlignment這種都屬於控件的固有屬性,而Grid.Row這種是添加進去的。這個屬性不在FrameworkElement這樣的基類中,而在DependencyObject中有一個字典,這個字典中保存所有擴展屬性的Key和Value,因爲保存它的是一個字典,所以它可以擴展,那麼設置Grid.Row就等價於下面的代碼

    txtQuestion.SetValue(Grid.RowProperty, 1)
    

    爲什麼不寫在基類中,要寫成這樣呢?很簡單,因爲不是所有的組件都需要這個屬性,只有在Grid中的組件有可能需要設置這個屬性,所以,做成可擴展的就不擾亂基類,也可以方便擴展。

元素樹

我們知道元素是以嵌套的方式進行構建的,構建的方式是:

  • 如果父元素實現了IList接口,就調用IList.Add
  • 如果父元素實現了IDictionary接口,就調用IDictionary.Add
  • 如果父元素使用了ContentProperty修飾,子元素設置對應的屬性

我們最需要關注的就是ContentProperty屬性,因爲ContentControl,ItemsControl,Panel基類都使用ContentProperty特性,這就是說幾乎所有的控件都使用ContentProperty,而IList接口的多是屬性等,在設置屬性的時候可以設置一個集合。

對於Grid中加入各種元素的情況,並不是因爲Grid是IList的集合,Grid支持的是ContentProperty,而能加入很多元素是因爲Grid繼承自Panel,Grid使用Panel渲染ContentProperty屬性,實現可以添加多個元素。Panel有一個Children屬性是一個集合,添加元素就是往Children中加入元素,看以下代碼

txtQuestion = new TextBox();
grid.Children.Add(txtQuestion);

那什麼父元素是IList的呢?之前就說過了,比如之前的GradientStopCollection,裏面可以添加很多個GradientStop

對於Grid我們說過了,那對於簡單元素,就更簡單了。TextBox的ContentProperty渲染的是Text屬性,Button的ContentProperty渲染的是Content屬性,這裏我們要討論以下Text屬性和Content屬性的區別了。

Text 屬性和 Content屬性

當我們指定控件中的文字的時候,我們發現有一些控件需要指定Text屬性,有一些控件卻是要指定Content屬性,那麼這兩個屬性有什麼區別呢?其實區別很簡單,Text屬性只能接受string類型的值,那麼控件中就只能添加文字,Content屬性就比較豐富多彩,可以放各種各樣的東西。看下面的例子說明一下。

<Button>
    <Button.Content>
        <Image Source="/Image/1.jpg"></Image>
    </Button.Content>
</Button>

實體字符集

< > " & 這些作爲XAML的關鍵字,不能在XAML中直接顯示,當我們要顯示這些字符的時候需要用到實體字符標記。
在這裏插入圖片描述

<Button>
    &lt;Click&gt;
</Button>
// 顯示出來的是<Click>

注意在代碼中設置Content不用遵循這個規則,而是需要遵循C#的轉義規則。

空白處理

默認

摺疊所有空白(打多少空格都只顯示一個),如果想要顯示所有的空格,有下面三種辦法

  1. 在代碼中設置的空格多少個都會被保留
  2. 使用 xml:space=“preserve” 屬性
  3. 在屬性中設置的多少個空格都會被保留
// 空格會保留
<TextBlock Text="[1     3      5         7]" />

// 空格會保留
<TextBox xml:space="preserve">
    1   2   3   4 
</TextBox>
// 空格不會保留
<TextBox>
    1   2   3   4 
</TextBox>

使用代碼控制XAML

// 加載XAML  XamlReader
using(FileStream fs = new FileStream(xamlFile. FileMode.Open))
{
    rootElement = (DependencyObject)XamlReader.Load(fs);
}
// 查找元素方法1
button1 = (Button)LogicalTreeHelper.FindLogicalNode(rootElement, "button1");
// 查找元素方法2
FrameworkElement frameworkElement = (FrameworkElement)rootElement;
button1 = (Button)frameworkElement.FindName("button1");

注意事項

  • 在XAML中加載的類,最好都能有一個無參數的構造函數,這樣的類適合XAML的加載
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章