XAML 的 樣式 style 應用
在這份筆記,將會記錄下 XAML 樣式 Style 的各種應用,這包括了
- 資源字典 Resource Dictionary 的使用
- 隱含樣式 (Implicit Styles)的用法
- 明確樣式 (Explicit Styles)的用法
- 繼承樣式
- 合併樣式與問題
- 使用 OnPlatfom 定義不同平台的樣式
- 在控制項內使用
Style
套用樣式
參考專案
資源字典 Resource Dictionary
在 XAML 裡面,使用資源字典可以定義各種不同的 styles, control templates, data templates, colors, and converters
您可以在 Application, Page, View 等等項目內,指定資源字典內容;
- 若您在 Application 類別內指定定義的資源字典項目,則這些項目是可以再全部的應用程式中使用,不過,那會有例外,那就是資源字典的合併機制。
- 若您在 Page 這類類別中指定定義的資源字典項目,則這些項目是可以在這個頁面中來使用
- 若您在某個 檢視控制項 View 或者 版面配置 Layout 中 指定定義的資源字典項目,則這些項目是可以在這個項目與其子項目內使用
全域樣式
只要在 App.xaml 檔案內使用
ResourceDictionary
定義的樣式,都可以在應用程式內使用,在這個範例專案內,App.xaml 檔案內容如下所示:
在這個 App.xaml 檔案內,定義了一個
PinkLabel
的樣式,另外,也使用了 OnPlatform
功能,依據當時執行的不同平台,定義了一個顏色與 Double 的資源值;接著,定義了一個 MyTitleLabel
樣式,其中這個樣式的 TextColor
& FontSize
這兩個屬性值,是由剛剛定義的資源值來取代。也就是說,當應用程式有套用了 MyTitleLabel
樣式的頁面,在不同的行動平台下執行( Android, iOS, UWP),這個樣式所表現出來的視覺效果是不一樣的。
以上資源定義都可以在整個應用程式內使用,不過,在
ResourceDictionary
項目 (Element) 有使用一個屬性 MergedWith
,其可以把其他定義的資源合併到這個 ResourceDictionary
下來使用。
不過,當在 App.xaml 下使用了
MergedWith
屬性,僅能夠在這個 App.xaml 下有效,但是整個應用程式是看不到使用 MergedWith
內合併進來的資源定義;關於 MergedWith
的應用,可以在頁面上來說明,就會更加清楚。App.xaml
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:themes="clr-namespace:MergedDict.Themes"
x:Class="MergedDict.App">
<Application.Resources>
<ResourceDictionary MergedWith="themes:RedTheme">
<!--在合併內定義的預設 Label 樣式,將無法在頁面中使用;
需要在頁面使用 MergedWith 引用合併樣式,才能夠使用
若要定義全域樣式,需要類似底下方式宣告(合併無法成為預設樣式)
-->
<Style x:Key="PinkLabel" TargetType="Label">
<Setter Property="TextColor" Value="Pink" />
<Setter Property="FontSize" Value="24" />
</Style>
<!--底下說明,如何根據不同平台特性,設定不同的樣式內容-->
<OnPlatform x:TypeArguments="Color" Android="Lime" iOS="Olive" WinPhone="Fuchsia" x:Key="ByPlatformColor" />
<OnPlatform x:TypeArguments="x:Double" Android="30" iOS="15" WinPhone="50" x:Key="ByPlatformSize" />
<Style x:Key="MyTitleLabel" TargetType="Label" BaseResourceKey="PinkLabel">
<Setter Property="TextColor" Value="{StaticResource ByPlatformColor}" />
<Setter Property="FontSize" Value="{StaticResource ByPlatformSize}" />
</Style>
</ResourceDictionary>
<!-- Application resource dictionary -->
</Application.Resources>
</Application>
獨立定義的資源字典
在這個專案內的資源夾
Themes
內,產生了三個獨立資源字典資源定義檔案 BlueTheme.xaml
,GreenTheme.xaml
, RedTheme.xaml
。這三個檔案分別定義了- 一個隱含樣式 (Implicit Styles),定義了所有
Label
檢視的文字顏色,字體大小為 24。所謂的隱含樣式,就是這個應用程式內所有的Label
檢視,都會使用這個隱含樣式的屬性設定來呈現。 - 一個明確樣式 (Explicit Styles),其代表名稱定義在
x:Key
內,這個明確樣式定義了字體顏色與字體大小為24。明確樣式則是當Label
檢視有定義需要使用這個樣式,其檢視才會使用這個樣式定義的屬性來呈現。
BlueTheme.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MergedDict.Themes.BlueTheme">
<Style TargetType="Label">
<Setter Property="TextColor" Value="Blue" />
<Setter Property="FontSize" Value="24" />
</Style>
<Style x:Key="BlueLabel" TargetType="Label">
<Setter Property="TextColor" Value="Blue" />
<Setter Property="FontSize" Value="24" />
</Style>
</ResourceDictionary>
GreenTheme.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MergedDict.Themes.GreenTheme">
<Style TargetType="Label">
<Setter Property="TextColor" Value="Green" />
<Setter Property="FontSize" Value="24" />
</Style>
<Style x:Key="GreenLabel" TargetType="Label">
<Setter Property="TextColor" Value="Green" />
<Setter Property="FontSize" Value="24" />
</Style>
</ResourceDictionary>
RedTheme.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MergedDict.Themes.RedTheme">
<Style TargetType="Label">
<Setter Property="TextColor" Value="Red" />
<Setter Property="FontSize" Value="24" />
</Style>
<Style x:Key="RedLabel" TargetType="Label">
<Setter Property="TextColor" Value="Red" />
<Setter Property="FontSize" Value="24" />
</Style>
</ResourceDictionary>
頁面樣式 MainPage
這個頁面是應用程式一啟動的時候,會顯示的頁面。
這個頁面的根項目為
ContentPage
,並且有定義資源字典;其分別定義了一個明確樣式 GrayLabel
,不過,在這個明確樣式的所有定義內容,是根據另外一個明確樣式 BlueLabel
繼承而來。
而明確樣式
LabelBlue
,其為在 ResourceDictionary
內,使用了屬性 MergedWith
合併了themes:BlueTheme
資源字典內容。
因為這裡合併了
themes:BlueTheme
資源字典,所以,在這個頁面下的所有子項目,都可以使用themes:BlueTheme
資源字典內定義的所有樣式,例如,這裡使用了 BlueLabel
樣式。
在
ContentPage
內的 ResourceDictionary
內,有個註解說明,若您將 <Style TargetType="Label">...</Style>
內容註解解除,那麼,Label
的隱含樣式將會使用原來 Xamarin.Forms 內建的樣式,並不會採用剛剛合併進來的隱含樣式定義,也就是說,若要覆蓋隱含樣式定義,合併進來的隱含樣式定義,不會影響這次定義。
在這個 XAML 範例中,展示了:隱含樣式、明確樣式、繼承樣式、合併樣式的使用方式。
若想要讓某個控制項套用明確樣式,可以使用
Style
屬性值來指定要套用的明確樣式。
最後,定義了一個按鈕,將會顯示另外一個頁面
Main2Page
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MergedDict"
xmlns:themes="clr-namespace:MergedDict.Themes"
Title="有資源字典合併"
x:Class="MergedDict.MainPage">
<ContentPage.Resources>
<!--在這個頁面,會合併其他樣式資源-->
<ResourceDictionary MergedWith="themes:BlueTheme">
<!--解除底下註解,將會導致預設 Label 的樣式為 Xamarin.Forms 內建,
不會從 全域樣式中繼承而來
-->
<!--<Style TargetType="Label">
<Setter Property="TextColor" Value="Purple" />
</Style>-->
<!--這個樣式,將會從 BlueLabel 繼承而來,而該樣式,則是合併而來-->
<Style x:Key="GrayLabel" TargetType="Label"
BasedOn="{StaticResource BlueLabel}">
<Setter Property="TextColor" Value="Gray" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout
VerticalOptions="Center"
HorizontalOptions="Center">
<!--加入其他 GreenLabel 樣式定義
若把底下 XAML 註解解除,則預設的 Label 樣式,會變成 Green
-->
<!--<StackLayout.Resources>
<ResourceDictionary MergedWith="themes:GreenTheme">
</ResourceDictionary>
</StackLayout.Resources>
<Label Text="使用 頁面GreenLabel 樣式"
VerticalOptions="Center"
HorizontalOptions="Center"
Style="{StaticResource GreenLabel}" />-->
<!--這裡 Label 的樣式,將會由頁面合併樣式中定義-->
<Label Text="沒有設定任何 樣式"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Label Text="使用 全域PinkLabel 樣式"
VerticalOptions="Center"
HorizontalOptions="Center"
Style="{StaticResource PinkLabel}" />
<Label Text="使用 頁面BlueLabel 樣式"
VerticalOptions="Center"
HorizontalOptions="Center"
Style="{StaticResource BlueLabel}" />
<!--底下 Label 定義會產生錯誤,這是因為 RedLabel
是在全域使用 合併方式進來的-->
<!--<Label Text="使用 頁面RedLabel 樣式"
VerticalOptions="Center"
HorizontalOptions="Center"
Style="{StaticResource RedLabel}" />-->
<Label Text="使用 GrayLabel 樣式(繼承 BlueLabel)"
VerticalOptions="Center"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Style="{StaticResource GrayLabel}"/>
<Label Text="使用 RedLabel 樣式(自已引用資源)"
VerticalOptions="Center"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Style="{StaticResource RedLabel}">
<Label.Resources>
<ResourceDictionary MergedWith="themes:RedTheme">
</ResourceDictionary>
</Label.Resources>
</Label>
<Label Text="沒有設定任何 樣式(自已引用資源)"
VerticalOptions="Center"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Style="{StaticResource RedLabel}">
<Label.Resources>
<ResourceDictionary MergedWith="themes:RedTheme">
</ResourceDictionary>
</Label.Resources>
</Label>
<Label Text="使用不同平台特性定義樣式"
VerticalOptions="Center"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Style="{StaticResource MyTitleLabel}"/>
<Button x:Name="btn" Text="下一頁" />
</StackLayout>
</ContentPage>
頁面樣式 Main2Page
當顯示了這個 Main2Page 頁面,所有在剛剛 MainPage 頁面中的定義樣式,將不會影響到這個 Main2Page 頁面;在 Main2Page 頁面,只有定義在 App.xaml 內的全域的樣式,才可以在這個 Main2Page頁面內使用。
在
ContentPage
項目內的 ResourceDictionary
有註解一段 XAML 樣式定義,若您解除這段樣式註解,將會在執行時其發生例外異常錯誤,會產生這樣的錯誤,是因為明確樣式 RedLabel
在這裡無法被參考到 (Xamarin.Forms.Xaml.XamlParseException: Position 16:14. StaticResource not found for key RedLabel
),就算參考了 BlueLabel
樣式,也是會一樣發生例外異常錯誤。Main2Page
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:themes="clr-namespace:MergedDict.Themes"
Title="沒有頁面資源字典"
x:Class="MergedDict.Main2Page">
<ContentPage.Resources>
<!--在這個頁面,將不會合併其他樣式資源-->
<ResourceDictionary >
<!--在底下定義,RedLabel會找不到,雖然在 App.xaml 中也合併該樣式,
不過,合併的全域樣式,無法在頁面中引用
解除底下註解,執行時候,將會產生例外異常
Xamarin.Forms.Xaml.XamlParseException: Position 16:14. StaticResource not found for key RedLabel
-->
<!--<Style x:Key="GrayLabel" TargetType="Label"
BasedOn="{StaticResource RedLabel}">
<Setter Property="TextColor" Value="Gray" />
</Style>-->
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout
VerticalOptions="Center"
HorizontalOptions="Center">
<!--這裡 Label 的樣式,將會由全域合併樣式中定義-->
<Label Text="沒有設定任何 樣式"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Label Text="使用 全域PinkLabel 樣式"
VerticalOptions="Center"
HorizontalOptions="Center"
Style="{StaticResource PinkLabel}" />
<!--
在全域 App.xaml 中,合併進來的明確樣式,無法在其他頁面中使用
若解除底下 Label 註解,執行期間,將會發生例外異常
-->
<!--<Label Text="使用 全域合併RedLabel 樣式"
VerticalOptions="Center"
HorizontalOptions="Center"
Style="{StaticResource RedLabel}" />-->
<Label Text="使用 RedLabel 樣式(自已引用資源)"
VerticalOptions="Center"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Style="{StaticResource RedLabel}">
<Label.Resources>
<ResourceDictionary MergedWith="themes:RedTheme">
</ResourceDictionary>
</Label.Resources>
</Label>
<Label Text="沒有設定任何 樣式(自已引用資源)"
VerticalOptions="Center"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Style="{StaticResource RedLabel}">
<Label.Resources>
<ResourceDictionary MergedWith="themes:RedTheme">
</ResourceDictionary>
</Label.Resources>
</Label>
</StackLayout>
</ContentPage>