使用 XAML 設定應用程式樣式

.NET 多平臺應用程式 UI (.NET MAUI) 應用程式通常包含多個具有相同外觀的控制件。 例如,應用程式可能會有多個 Label 具有相同字型選項和版面設定選項的實例:

<Label Text="These labels"
       HorizontalOptions="Center"
       VerticalOptions="Center"
       FontSize="18" />
<Label Text="are not"
       HorizontalOptions="Center"
       VerticalOptions="Center"
       FontSize="18" />
<Label Text="using styles"
       HorizontalOptions="Center"
       VerticalOptions="Center"
       FontSize="18" />

在此範例中,每個 Label 物件都有相同的屬性值,可控制 所 Label顯示之文字的外觀。 不過,設定每個個別控件的外觀可能會重複且容易出錯。 相反地,可以建立定義外觀的樣式,然後套用至必要的控件。

樣式簡介

應用程式可以使用 類別將屬性值集合分組成一個物件,然後套用至多個視覺元素,以設定應用程式樣式 Style 。 這有助於減少重複標記,並允許應用程式外觀更容易變更。

雖然樣式主要是針對以 XAML 為基礎的應用程式所設計,但它們也可以在 C# 中建立:

  • Style 在 XAML 中建立的物件通常會定義在 ResourceDictionary 指派給 Resources 控件、頁面或 Resources 應用程式集合集合的 中。
  • Style 在 C# 中建立的物件通常會定義於頁面的 類別中,或在可全域存取的類別中定義。

選擇要在何處定義 Style 會影響其可使用的位置:

  • Style 在控件層級定義的實例只能套用至控件及其子系。
  • Style 在頁面層級定義的實例只能套用至頁面及其子系。
  • Style 在應用程式層級定義的實例可以在整個應用程式中套用。

每個 Style 物件都包含一或多個 Setter 物件的集合,每個物件都有 SetterPropertyValueProperty 為樣式所套用元素的可繫結屬性名稱,且 Value 為套用至屬性的值。

每個 Style 物件可以是 明確隱含

  • 明確Style對像是藉由指定 TargetTypex:Key 值,以及將目標元素的 Style 屬性設定為x:Key參考來定義。 如需詳細資訊,請參閱 明確樣式
  • 隱含Style對像是藉由只TargetType指定 來定義。 然後,物件 Style 會自動套用至該類型的所有專案。 不過,的 TargetType 子類別不會自動 Style 套用 。 如需詳細資訊,請參閱 隱含樣式

建立 Style 時,一律需要 TargetType 屬性。 下列範例顯示 明確的 樣式:

<Style x:Key="labelStyle" TargetType="Label">
    <Setter Property="HorizontalOptions" Value="Center" />
    <Setter Property="VerticalOptions" Value="Center" />
    <Setter Property="FontSize" Value="18" />
</Style>

若要套用 Style,目標物件必須是 VisualElement 符合 TargetType 的 屬性值的 Style

<Label Text="Demonstrating an explicit style" Style="{StaticResource labelStyle}" />

檢視階層中較低樣式的優先順序高於較高定義的樣式。 例如,Style將 設定Label.TextColorRed為 在應用層級的 ,將會由設定Label.TextColorGreen的頁面層級樣式覆寫。 同樣地,頁面層級樣式會由控件層級樣式覆寫。 此外,如果 Label.TextColor 直接在控件屬性上設定,這會優先於任何樣式。

樣式不會回應屬性變更,而且在應用程式持續期間維持不變。 不過,應用程式可以使用動態資源,在運行時間動態響應樣式變更。 如需詳細資訊,請參閱 動態樣式

明確樣式

若要在頁面層級建立 StyleResourceDictionary必須將 新增至頁面,然後可以包含一或多個Style宣告。ResourceDictionary Style藉由為其宣告提供x:Key屬性,以明確表示 ,這會在 中ResourceDictionary提供描述性索引鍵。 然後,必須藉由設定其Style屬性,將明確樣式套用至特定的視覺元素。

下列範例顯示頁面 的 ResourceDictionary中明確樣式,並套用至頁面Label的物件:

<ContentPage ...>
    <ContentPage.Resources>
        <Style x:Key="labelRedStyle"
               TargetType="Label">
            <Setter Property="HorizontalOptions" Value="Center" />
            <Setter Property="VerticalOptions" Value="Center" />
            <Setter Property="FontSize" Value="18" />
            <Setter Property="TextColor" Value="Red" />
        </Style>
        <Style x:Key="labelGreenStyle"
               TargetType="Label">
            <Setter Property="HorizontalOptions" Value="Center" />
            <Setter Property="VerticalOptions" Value="Center" />
            <Setter Property="FontSize" Value="18" />
            <Setter Property="TextColor" Value="Green" />
        </Style>
        <Style x:Key="labelBlueStyle"
               TargetType="Label">
            <Setter Property="HorizontalOptions" Value="Center" />
            <Setter Property="VerticalOptions" Value="Center" />
            <Setter Property="FontSize" Value="18" />
            <Setter Property="TextColor" Value="Blue" />
        </Style>
    </ContentPage.Resources>
    <StackLayout>
        <Label Text="These labels"
               Style="{StaticResource labelRedStyle}" />
        <Label Text="are demonstrating"
               Style="{StaticResource labelGreenStyle}" />
        <Label Text="explicit styles,"
               Style="{StaticResource labelBlueStyle}" />
        <Label Text="and an explicit style override"
               Style="{StaticResource labelBlueStyle}"
               TextColor="Teal" />
    </StackLayout>
</ContentPage>

在此範例中,會 ResourceDictionary 定義在頁面對象上明確設定的 Label 三種樣式。 每個 Style 都用來以不同的色彩顯示文字,同時設定字型大小和水平和垂直版面配置選項。 每個Style都會使用StaticResource標記延伸來設定其Style屬性,以套用至不同的 Label 。 此外,雖然最後 Label 有一個 Style 設定,但它也會將 屬性覆寫 TextColor 為不同的 Color 值。

隱含樣式

若要在頁面層級建立 StyleResourceDictionary必須將 新增至頁面,然後可以包含一或多個Style宣告。ResourceDictionary Style透過未指定x:Key屬性,以隱含方式建立 。 然後,樣式會套用至範圍視覺效果元素中,這些視覺效果元素與完全相符 TargetType ,但不適用於衍生自 TargetType 值的專案。

下列程式代碼範例顯示頁面 的 ResourceDictionary隱含樣式,並套用至頁面Entry的物件:

<ContentPage ...>
    <ContentPage.Resources>
        <Style TargetType="Entry">
            <Setter Property="HorizontalOptions" Value="Fill" />
            <Setter Property="VerticalOptions" Value="Center" />
            <Setter Property="BackgroundColor" Value="Yellow" />
            <Setter Property="FontAttributes" Value="Italic" />
            <Setter Property="TextColor" Value="Blue" />
        </Style>
    </ContentPage.Resources>
    <StackLayout>
        <Entry Text="These entries" />
        <Entry Text="are demonstrating" />
        <Entry Text="implicit styles," />
        <Entry Text="and an implicit style override"
               BackgroundColor="Lime"
               TextColor="Red" />
        <local:CustomEntry Text="Subclassed Entry is not receiving the style" />
    </StackLayout>
</ContentPage>

在此範例中,會ResourceDictionary定義在頁面Entry物件上隱含設定的單一隱含樣式。 Style用來在黃色背景上顯示藍色文字,同時設定其他外觀選項。 在 Style 未指定屬性的情況下,會將 新增至頁面 ResourceDictionaryx:Key 。 因此, Style 會隱含地套用至所有 Entry 對象,因為它們 TargetType 完全符合 的 Style 屬性。 不過, Style 不會套用至 CustomEntry 物件,這是子類別化 Entry。 此外,第四 Entry 個會 BackgroundColor 覆寫樣式的 和 TextColor 屬性至不同的 Color 值。

將樣式套用至衍生類型

屬性 Style.ApplyToDerivedTypes 可讓樣式套用至衍生自 屬性所參考基底型別的 TargetType 控件。 因此,將此屬性設定為 true 可讓單一樣式以多個類型為目標,前提是型別衍生自 屬性中指定的 TargetType 基底型別。

下列範例顯示將實例的背景色彩設定為紅色的 Button 隱含樣式:

<Style TargetType="Button"
       ApplyToDerivedTypes="True">
    <Setter Property="BackgroundColor"
            Value="Red" />
</Style>

將此樣式放在頁面層級 ResourceDictionary 會導致它套用至頁面上的所有 Button 物件,也套用至衍生自 Button的任何控件。 不過,如果 ApplyToDerivedTypes 屬性保持未設定,則樣式只會套用至 Button 物件。

全域樣式

您可以將樣式新增至應用程式的資源字典,以全域方式定義樣式。 然後,這些樣式可以在整個應用程式中取用,並協助避免跨頁面和控件的樣式重複。

下列範例示範 Style 在應用程式層級定義的 :


<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:Styles"
             x:Class="Styles.App">
    <Application.Resources>        
        <Style x:Key="buttonStyle" TargetType="Button">
            <Setter Property="HorizontalOptions"
                        Value="Center" />
            <Setter Property="VerticalOptions"
                        Value="CenterAndExpand" />
            <Setter Property="BorderColor"
                        Value="Lime" />
            <Setter Property="CornerRadius"
                        Value="5" />
            <Setter Property="BorderWidth"
                        Value="5" />
            <Setter Property="WidthRequest"
                        Value="200" />
            <Setter Property="TextColor"
                        Value="Teal" />
        </Style>
    </Application.Resources>
</Application>

在此範例中,會 ResourceDictionary 定義單 一明確 樣式, buttonStyle用來設定對象的外觀 Button

注意

全域樣式可以是 明確隱含的。

下列範例顯示頁面取用 buttonStyle 頁面上 Button 的物件:

<ContentPage ...>
    <StackLayout>
        <Button Text="These buttons"
                Style="{StaticResource buttonStyle}" />
        <Button Text="are demonstrating"
                Style="{StaticResource buttonStyle}" />
        <Button Text="application styles"
                Style="{StaticResource buttonStyle}" />
    </StackLayout>
</ContentPage>

樣式繼承

樣式可以繼承自其他樣式,以減少重複並啟用重複使用。 這可藉由將 Style.BasedOn 屬性設定為現有的 Style來達成。 在 XAML 中,將 屬性設定 BasedOnStaticResource 參考先前建立 Style的標記延伸,即可達成此目的。

繼承自基底樣式的樣式可以包含 Setter 新屬性的實例,或使用它們來覆寫基底樣式中的 setter。 此外,繼承自基底樣式的樣式必須以相同類型為目標,或是衍生自基底樣式目標類型的類型。 例如,如果基底樣式以對象為目標 View ,則以基底樣式為基礎的樣式可以以 View 衍生自 View 類別的物件或類型為目標,例如 LabelButton 物件。

樣式只能繼承於檢視階層中相同層級或更高層級的樣式。 這表示:

  • 應用層級樣式只能繼承自其他應用層級樣式。
  • 頁面層級樣式可以繼承自應用層級樣式和其他頁面層級樣式。
  • 控件層級樣式可以繼承自應用層級樣式、頁面層級樣式和其他控件層級樣式。

下列範例顯示 明確的 樣式繼承:

<ContentPage ...>
    <ContentPage.Resources>
        <Style x:Key="baseStyle"
               TargetType="View">
            <Setter Property="HorizontalOptions" Value="Center" />
            <Setter Property="VerticalOptions" Value="Center" />
        </Style>
    </ContentPage.Resources>
    <StackLayout>
        <StackLayout.Resources>
            <Style x:Key="labelStyle"
                   TargetType="Label"
                   BasedOn="{StaticResource baseStyle}">
                <Setter Property="FontSize" Value="18" />
                <Setter Property="FontAttributes" Value="Italic" />
                <Setter Property="TextColor" Value="Teal" />
            </Style>
            <Style x:Key="buttonStyle"
                   TargetType="Button"
                   BasedOn="{StaticResource baseStyle}">
                <Setter Property="BorderColor" Value="Lime" />
                <Setter Property="CornerRadius" Value="5" />
                <Setter Property="BorderWidth" Value="5" />
                <Setter Property="WidthRequest" Value="200" />
                <Setter Property="TextColor" Value="Teal" />
            </Style>
        </StackLayout.Resources>
        <Label Text="This label uses style inheritance"
               Style="{StaticResource labelStyle}" />
        <Button Text="This button uses style inheritance"
                Style="{StaticResource buttonStyle}" />
    </StackLayout>
</ContentPage>

在此範例中,目標baseStyleView物件會設定 HorizontalOptionsVerticalOptions 屬性。 baseStyle不會直接在任何控制項上設定 。 相反地, labelStylebuttonStyle 繼承自它,設定額外的可系結屬性值。 和 labelStyle 物件接著會在和 buttonStyleButtonLabel設定。

重要

隱含樣式可以衍生自明確樣式,但無法從隱含樣式衍生明確樣式。

動態樣式

樣式不會回應屬性變更,而且在應用程式持續期間維持不變。 例如,將 Style 指派給可視化項目之後,如果其中一個 Setter 物件已修改、移除或新增 Setter ,則不會將變更套用至視覺效果專案。 不過,應用程式可以使用動態資源,在運行時間動態響應樣式變更。

標記 DynamicResource 延伸類似於 StaticResource 中的標記延伸,這兩者都使用字典索引鍵從 ResourceDictionary擷取值。 不過,雖然 StaticResource 會執行單一字典查閱,但 DynamicResource 會維護字典索引鍵的連結。 因此,如果取代與索引鍵相關聯的字典專案,則會將變更套用至視覺專案。 這可讓應用程式進行運行時間樣式變更。

下列範例顯示 動態 樣式:

<ContentPage ...>
    <ContentPage.Resources>
        <Style x:Key="baseStyle"
               TargetType="View">
            <Setter Property="VerticalOptions" Value="Center" />
        </Style>
        <Style x:Key="blueSearchBarStyle"
               TargetType="SearchBar"
               BasedOn="{StaticResource baseStyle}">
            <Setter Property="FontAttributes" Value="Italic" />
            <Setter Property="PlaceholderColor" Value="Blue" />
        </Style>
        <Style x:Key="greenSearchBarStyle"
               TargetType="SearchBar">
            <Setter Property="FontAttributes" Value="None" />
            <Setter Property="PlaceholderColor" Value="Green" />
        </Style>
    </ContentPage.Resources>
    <StackLayout>
        <SearchBar Placeholder="SearchBar demonstrating dynamic styles"
                   Style="{DynamicResource blueSearchBarStyle}" />
    </StackLayout>
</ContentPage>

在這裡範例中 SearchBar ,物件會使用 DynamicResource 標記延伸來設定 Style 具名 blueSearchBarStyle的 。 SearchBar接著,可以在程式代碼中更新其Style定義:

Resources["blueSearchBarStyle"] = Resources["greenSearchBarStyle"];

在此範例中,定義 blueSearchBarStyle 會更新為使用定義中的值 greenSearchBarStyle 。 執行此程式代碼時, SearchBar 將會更新 為使用 SettergreenSearchBarStyle定義的物件。

動態樣式繼承

您無法使用 Style.BasedOn 屬性,從動態樣式衍生樣式。 相反地,類別 Style 會包含 BaseResourceKey 屬性,可以設定為可能會動態變更其值的字典索引鍵。

下列範例顯示 動態 樣式繼承:

<ContentPage ...>
    <ContentPage.Resources>
        <Style x:Key="baseStyle"
               TargetType="View">
            <Setter Property="VerticalOptions" Value="Center" />
        </Style>
        <Style x:Key="blueSearchBarStyle"
               TargetType="SearchBar"
               BasedOn="{StaticResource baseStyle}">
            <Setter Property="FontAttributes" Value="Italic" />
            <Setter Property="TextColor" Value="Blue" />
        </Style>
        <Style x:Key="greenSearchBarStyle"
               TargetType="SearchBar">
            <Setter Property="FontAttributes" Value="None" />
            <Setter Property="TextColor" Value="Green" />
        </Style>
        <Style x:Key="tealSearchBarStyle"
               TargetType="SearchBar"
               BaseResourceKey="blueSearchBarStyle">
            <Setter Property="BackgroundColor" Value="Teal" />
            <Setter Property="CancelButtonColor" Value="White" />
        </Style>
    </ContentPage.Resources>
    <StackLayout>
        <SearchBar Text="SearchBar demonstrating dynamic style inheritance"
                   Style="{StaticResource tealSearchBarStyle}" />
    </StackLayout>
</ContentPage>

在這裡範例中 SearchBar ,物件會使用 StaticResource 標記延伸來參考 Style 具名 tealSearchBarStyle的 。 這會 Style 設定額外屬性,並使用 BaseResourceKey 屬性來參考 blueSearchBarStyleDynamicResource不需要標記延伸,因為 tealSearchBarStyle 不會變更,除非Style它衍生自 。 因此, tealSearchBarStyle 會在基底樣式變更時維護 和的連結 blueSearchBarStyle

定義可以在程式 blueSearchBarStyle 代碼中更新:

Resources["blueSearchBarStyle"] = Resources["greenSearchBarStyle"];

在此範例中,定義 blueSearchBarStyle 會更新為使用定義中的值 greenSearchBarStyle 。 執行此程式代碼時, SearchBar 將會更新 為使用 SettergreenSearchBarStyle定義的物件。

樣式類別

樣式類別可讓多個樣式套用至控件,而不需採用樣式繼承。

您可以將上的 Style 屬性設定Class為 ,以表示類別名稱的 ,string來建立樣式類別。 透過使用 x:Key 屬性來定義明確樣式,這項功能的優點是可將多個樣式類別套用至 VisualElement

重要

如果樣式以不同的類型為目標,則多個樣式可以共用相同的類別名稱。 這可讓多個樣式類別,其名稱相同,以不同類型為目標。

下列範例顯示三 BoxView 個樣式類別,以及一個 VisualElement 樣式類別:

<ContentPage ...>
    <ContentPage.Resources>
        <Style TargetType="BoxView"
               Class="Separator">
            <Setter Property="BackgroundColor"
                    Value="#CCCCCC" />
            <Setter Property="HeightRequest"
                    Value="1" />
        </Style>

        <Style TargetType="BoxView"
               Class="Rounded">
            <Setter Property="BackgroundColor"
                    Value="#1FAECE" />
            <Setter Property="HorizontalOptions"
                    Value="Start" />
            <Setter Property="CornerRadius"
                    Value="10" />
        </Style>    

        <Style TargetType="BoxView"
               Class="Circle">
            <Setter Property="BackgroundColor"
                    Value="#1FAECE" />
            <Setter Property="WidthRequest"
                    Value="100" />
            <Setter Property="HeightRequest"
                    Value="100" />
            <Setter Property="HorizontalOptions"
                    Value="Start" />
            <Setter Property="CornerRadius"
                    Value="50" />
        </Style>

        <Style TargetType="VisualElement"
               Class="Rotated"
               ApplyToDerivedTypes="true">
            <Setter Property="Rotation"
                    Value="45" />
        </Style>        
    </ContentPage.Resources>
</ContentPage>

在此範例中 Separator,、 RoundedCircle 樣式類別會將每個屬性設定 BoxView 為特定值。 樣式 Rotated 類別具有 TargetTypeVisualElement,這表示它只能套用至 VisualElement 實例。 不過,其 ApplyToDerivedTypes 屬性會設定為 true,以確保它可以套用至衍生自 VisualElement的任何控制件,例如 BoxView。 如需將樣式套用至衍生類型的詳細資訊,請參閱 將樣式套用至衍生類型

將類型為IList<string>的控件屬性設定StyleClass為樣式類別名稱清單,即可取用樣式類別。 如果控件的類型符合 TargetType 樣式類別的 ,則會套用樣式類別。

下列範例顯示三 BoxView 個實例,每個實例都設定為不同的樣式類別:

<ContentPage ...>
    <ContentPage.Resources>
        ...
    </ContentPage.Resources>
    <StackLayout>
        <BoxView StyleClass="Separator" />       
        <BoxView WidthRequest="100"
                 HeightRequest="100"
                 HorizontalOptions="Center"
                 StyleClass="Rounded, Rotated" />
        <BoxView HorizontalOptions="Center"
                 StyleClass="Circle" />
    </StackLayout>
</ContentPage>    

在此範例中,第一個 BoxView 樣式為線條分隔符,而第三 BoxView 個則為圓形。 第二 BoxView 個樣式類別已套用兩個樣式類別,可提供圓角並旋轉 45 度:

Screenshot of BoxViews styled with style classes.

重要

多個樣式類別可以套用至控制元件,因為 StyleClass 屬性的類型為 IList<string>。 發生這種情況時,樣式類別會以遞增清單順序套用。 因此,當多個樣式類別設定相同的屬性時,位於最高清單位置的樣式類別中的 屬性會優先。