[Windows 8|XAML] XAML元件屬性重複使用-資源(Resources)與樣式(Style)介紹

Published: 10/01/2013, Last Updated: 10/01/2013

前言


在學習開發XAML時,有時候畫面上某些元件可能會需要設定一樣的屬性(如:我有三個TextBlock都需要設定為顯示紅色字體,文字大小要32),但是一個一個設定不僅浪費時間,如果要做修改時,也要對每一個元件都重複做同樣的修改,耗時也費力。

而在XAML有一個資源的概念,可以把類似的這樣的元件屬性、樣式做一個事先的定義,然後再去對元件做指定套用。

在此篇主要會以在頁面資源(FrameworkElement.Resources)使用為主

資源(Resources)


如前言所述,有時候我們會遇到這樣的需求,這個時候資源的概念便派上用場了!

透過資源,我們可以事先透過定義好要套用到元件上的屬性,並且這總地億的資源可以重複使用!

資源是一種共享、反覆利用元素、屬性的機制。

可以用來定義的資源包含:

樣式(Style)與範本(Template)、筆刷(Brush)、故事版腳本(Storyboard)...等等,這些都各式是資源的一種

而以下我們會以介紹樣式(Style)為主,因為大多時候我們主要是針對XAML的元件(Button、Image、TextBlock、TextBox...)屬性做設定。

直接資源與應用程式資源

資源包含兩種類型:直接資源與頁面資源

直接資源:

FrameworkElement.Resources,或稱頁面資源,是針對單一頁面做資源配置,更詳細的說頁面資源只能被用在單一XAML頁面中的元件使用,在這邊,控制項的元件(Grid、StackPanel、Button、Rectangle等等)都包含Resources屬性(繼承自FrameworkElement),於是我們便可以在Resources標籤中定義我們想要使用的資源。

拿下圖來例子看的話,頁面資源分別就是XAML頁面A與頁面B,而頁面A中的資源定義只有頁面A看的到,同理頁面B的資源也只有頁面B的元件看的到,頁面A無法使用頁面B中所定義的資源。

但是一般會建議把資源的定義放在Page,因為這樣的好處是可以方便我們對所有的資源做一個管理。

假若今天我的XAML頁中的程式很大,這時在Grid中有資源,Button中有資源,並且我都需要做一些變動,這樣不就要來來回回的移動調整了嗎,所以建議把資源的定義放在Page,因為這樣的好處是可以方便我們對所有的資源做一個管理。

應用程式資源:

Application.Resources,可以使資源的定義被整個Application所看到,如果我在應用程式資源定義的話,以上面圖來看,的頁面A與頁面B,這兩個XAML頁面都可以使用我在應用程式資源事先定義Resources。

而在這邊我們先介紹直接資源,應用程式資源的部分會再另一篇做介紹。

那麼究竟使用資源是什麼樣的感覺呢?


以直接資源(頁面資源)為範例:

我們在Grid元件下拉入兩個TextBlock,然後我們透過Resources的定義來讓TextBlock套用同時改變!

這是原先不使用Resources的程式碼:

<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="32" Foreground="Red"  Margin="310,411,0,0"  Text="TextBlock"/>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="32" Foreground="Red"   Margin="677,411,0,0"  Text="TextBlock" />
        

再來是透過定義資源的方式:

<Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="32"/>
                <Setter Property="Foreground" Value="Red"/>
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="VerticalAlignment" Value="Top"/>
            </Style>
</Grid.Resources>
<TextBlock  Margin="310,411,0,0"  Text="TextBlock"/>
<TextBlock  Margin="677,411,0,0"  Text="TextBlock" />

結果顯示:

上面的範例中,原先我們對兩個TextBlock都做了一樣的屬性設定,但是在使用資源時,我們則是透過Style標籤的定義來讓後面的TextBlock一次套用。

而由於是使用頁面資源,我們需要讓被定義的Style資源被Resources標籤包覆住,因為在這個範例中,XAML非常少,且剛好兩個TextBlock是屬於Grid子標籤,所以便利用Grid.Resources作為我們定義用的區塊(但是再次提醒,一邊會建議放在Page中,Page.Resources,最後會提到)。

好的,在這邊我們進入此篇文章的另一個重點,樣式(Style)資源

Style(樣式)

樣式主要用來定義XAML元件中的屬性值,例如我的按鈕要什麼樣的文字大小,文字字型,文字顏色等等屬性。

樣式也是一種資源,所以需被放在有Resources屬性的標籤中。

以下讓我們再看一次前面的程式碼:

<Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="32"/>
                <Setter Property="Foreground" Value="Red"/>
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="VerticalAlignment" Value="Top"/>
            </Style>
</Grid.Resources>

Style:

是定義樣式用的標籤,其中TargetType這個屬性是用來指定你設定的元件,但是TargetType因為指定元件,所以全部在這個XAML頁面下的元件都會被套用。

<Style TargetType="TextBlock">

已上面這段程式碼來看,代表著我要對所有TextBlock的元件套用這個樣式

Setter:

設定Style中TargetType所指定的元件要變動的屬性,要改變的方式則是透過Property指定屬性,Value修改參數,以上面的例子來看:

<Setter Property="FontSize" Value="32"/>

修改字體就是TextBlock的FontSize大小為32,所以想要定義屬性即可以透過這個Setter標籤來完成

那麼回到先前所提到的,TargetType因為指定元件,所以全部在這個XAML頁面下的元件都會被套用,代表著我要對所有TextBlock的元件套用這個樣式。

如果今天我只要對特定的TextBlock修改要怎麼辦?

使用X:Key與StaticResource延伸標記修改特定元件的屬性

這次,我們來修改一下上面的範例,改成只要對左邊的TextBlock顯示紅色,右邊的TextBlock則顯示黃色文字。

<Grid.Resources>
            <Style TargetType="TextBlock" x:Key="RedColor">
                <Setter Property="FontSize" Value="32"/>
                <Setter Property="Foreground" Value="Red"/>
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="VerticalAlignment" Value="Top"/>
            </Style>
            <Style TargetType="TextBlock" x:Key="YellowColor">
                <Setter Property="FontSize" Value="32"/>
                <Setter Property="Foreground" Value="Yellow"/>
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="VerticalAlignment" Value="Top"/>
            </Style>
 </Grid.Resources>
<TextBlock  Margin="310,411,0,0"  Text="TextBlock" Style="{StaticResource RedColor}"/>
<TextBlock  Margin="677,411,0,0"  Text="TextBlock" Style="{StaticResource YellowColor}"/>

在上面你會看到,我們增加了新的程式碼,在Style中一個叫做X:Key的關鍵字與TextBlock中加入Style="{StaticResource xxx}"

X:Key:

在Style中加入這段程式,代表我要對這個資源指定索引鍵,而這個索引鍵可以做為之後與個別元件做樣式的參考

Style="{StaticResource xxx}":

StaticResource 是一種延伸標記,透過這串語法,把先前所設定的X:Key的索引鍵做設定,可以取得事先定義好的Resources屬性

所以在上面的範例中我們分別定義了YellowColor的樣式與RedColor的樣式,並把Key值分別指定到兩個TextBlock的Style="{StaticResource xxx}中。

透過這樣一個對樣式

1.指定x:key與在元件中

2.在元件中設定Style,並做StaticResource 延伸標記參考x:key至我們事先定義好的Style資源

即可完成。

資源繼承

在上面的X:Key範例中,兩個TextBlock的差異只在顏色,而為了修改顏色,指定到不同的TextBlock,所以我們透過X:Key與StaticResource延伸標記來完成,但是你會看到有重複的Code,而這樣就違背了我們原先的美意,因此在這邊要介紹資源的繼承,來讓重複的XAML可以減少

使用BasedOn

BasedOn就如同物件導向中的繼承概念一樣,可以把婦類別的功能與成員屬性繼承下來:

<Grid.Resources>
            <Style TargetType="TextBlock" x:Key="Normal">
                <Setter Property="FontSize" Value="32"/>
                <Setter Property="Foreground" Value="Red"/>
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="VerticalAlignment" Value="Top"/>
            </Style>
            <Style TargetType="TextBlock" x:Key="YellowColor" BasedOn="{StaticResource Normal}">
                <Setter Property="Foreground" Value="Yellow"/>
            </Style>
            <Style TargetType="TextBlock" x:Key="RedColor" BasedOn="{StaticResource Normal}">
                <Setter Property="Foreground" Value="Red"/>
            </Style>
</Grid.Resources>
 <TextBlock  Margin="310,411,0,0"  Text="TextBlock" Style="{StaticResource RedColor}"/>
 <TextBlock  Margin="677,411,0,0"  Text="TextBlock" Style="{StaticResource YellowColor}"/>

X:Key="Normal"的樣式就是TextBlock共同的屬性設定,為了能夠辨別到父樣式而繼承下來,所以才會需要X:Key="Normal"

而下面的YellowColor與RedColor索引鍵樣式則是透過BasedOn與StaticResource延伸標記繼承下來,並加入新的屬性樣式,透過這樣的模式減少重複的屬性設定!

為了呼應我們前面提到的資源可重複使用性,這邊我而外再加入一個TextBlock,並對他套用YellowColor這個樣式,如下程式碼與結果,即便是有索引鍵的資源也是可以重複給別的元件使用!

 <Grid.Resources>
            <Style TargetType="TextBlock" x:Key="Normal">
                <Setter Property="FontSize" Value="32"/>
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="VerticalAlignment" Value="Top"/>
            </Style>
            <Style TargetType="TextBlock" x:Key="YellowColor" BasedOn="{StaticResource Normal}">
                <Setter Property="Foreground" Value="Yellow"/>
            </Style>
            <Style TargetType="TextBlock" x:Key="RedColor" BasedOn="{StaticResource Normal}">
                <Setter Property="Foreground" Value="Red"/>
            </Style>
</Grid.Resources>
<TextBlock  Margin="310,411,0,0"  Text="TextBlock" Style="{StaticResource YellowColor}"/>
<TextBlock  Margin="677,411,0,0"  Text="TextBlock" Style="{StaticResource RedColor}"/>
 <TextBlock  Margin="983,411,0,0"  Text="TextBlock" Style="{StaticResource YellowColor}"/>

把頁面資源放在Page.Resources中

最後,在前面提到如果是單一頁面的話,基本上會建議把Resources放在Page,因為Page是XAML頁面的根,所以可以確保我整個頁面下的元件根可能被指定套上資源,另外一個好處則是,方便所以的樣式資源可以放在一起統一管理。

所以如下的XAML程式碼,便是移動到Page的Resources下,整個Windows 8 App的XAML檔最外層是Page,所以我們在這邊加入了Page.Resources的標籤,並把Style樣式定義包覆在其中。

<Page.Resources>
        <Style TargetType="TextBlock" x:Key="Normal">
            <Setter Property="FontSize" Value="32"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Top"/>
        </Style>
        <Style TargetType="TextBlock" x:Key="YellowColor" BasedOn="{StaticResource Normal}">
            <Setter Property="Foreground" Value="Yellow"/>
        </Style>
        <Style TargetType="TextBlock" x:Key="RedColor" BasedOn="{StaticResource Normal}">
            <Setter Property="Foreground" Value="Red"/>
        </Style>
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}" HorizontalAlignment="Left" Width="1366">
        <TextBlock  Margin="380,397,0,0"  Text="TextBlock" Style="{StaticResource YellowColor}"/>
        <TextBlock  Margin="614,397,0,0"  Text="TextBlock" Style="{StaticResource RedColor}"/>
        <TextBlock  Margin="832,397,0,0"  Text="TextBlock" Style="{StaticResource YellowColor}"/>
</Grid>

結論


善用資源可以讓你的XAML頁面整齊,捨去重複的程式碼,同時若你要重修調整或修改維護你的XAML程式時,也可以加快你的修改速度(因為你不再需要一個一個去修改)。

參考資料:

XAML資源

Product and Performance Information

1

Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for Intel microprocessors. Please refer to the applicable product User and Reference Guides for more information regarding the specific instruction sets covered by this notice.

Notice revision #20110804