在學習開發XAML時,有時候畫面上某些元件可能會需要設定一樣的屬性(如:我有三個TextBlock都需要設定為顯示紅色字體,文字大小要32),但是一個一個設定不僅浪費時間,如果要做修改時,也要對每一個元件都重複做同樣的修改,耗時也費力。
而在XAML有一個資源的概念,可以把類似的這樣的元件屬性、樣式做一個事先的定義,然後再去對元件做指定套用。
在此篇主要會以在頁面資源(FrameworkElement.Resources)使用為主
前言
在學習開發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程式時,也可以加快你的修改速度(因為你不再需要一個一個去修改)。
參考資料:
文章中的敘述如有觀念不正確錯誤的部分,歡迎告知指正 謝謝 =)
另外要轉載請附上出處 感謝