XAML 樣式

您可以使用 XAML 架構,以許多方式自訂應用程式的外觀。 樣式可讓您設定控制項屬性,並在多個控制項重複使用這些設定來擁有一致的外觀。

WinUI 和樣式

從 WinUI 2.2 開始,我們已使用 Windows UI 程式庫 (WinUI) 在 UI 元件之間提供新的視覺樣式更新。 如果您注意到 UI 未更新為最新的樣式,請務必更新為最新的 WinUI NuGet 套件。

從 WinUI 2.6 開始,我們為大部分的控制項提供新的樣式,以及新的版本設定系統,可讓您視需要還原為先前的控制項樣式。 建議您使用新的樣式,因為它們更符合 Windows 的設計方向。 不過,如果您的案例無法支援新的樣式,則舊版仍可供使用。

使用 WinUI 版本 2 時,可以透過設定包含在 Application.Resources 中的 XamlControlsResources 上的 ControlsResourcesVersion 屬性來變更樣式版本。 ControlsResourcesVersion 預設為列舉值 Version2

將此值設定為 Version1 會導致 XamlControlsResources 載入先前的樣式版本,而不是最新 WinUI 版本所使用的新樣式。 不支援在執行階段變更此屬性,而且 VisualStudio 的熱重載功能將無法運作;不過,控制項樣式將在重建應用程式之後變更。

<Application.Resources>
    <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" 
                           ControlsResourcesVersion="Version1"/>
</Application.Resources>

樣式基本概念

使用樣式將視覺化屬性設定擷取至可重複使用的資源。 以下是顯示 3 個按鈕的範例,其中包含設定 BorderBrushBorderThicknessForeground 屬性的樣式。 透過套用樣式即可讓控制項看起來相同,無須分開設定每個控制項的這些屬性。

Screenshot of three styled buttons arranged side by side.

可以在 XAML 中為控制項定義樣式內嵌,或定義為可重複使用資源。 在個別頁面的 XAML 檔案、App.xaml 檔案或個別資源字典 XAML 檔案中定義資源。 資源字典 XAML 檔案可以跨應用程式共用,而且可以在單一應用程式中合併多個資源字典。 定義資源的位置會決定其可使用的範圍。 頁面層級資源只能在定義它們的頁面中使用。 如果在 App.xaml 和頁面中定義具有相同索引鍵的資源,則頁面中的資源會覆寫 App.xaml 中的資源。 如果資源是在不同的資源字典檔案中定義,則其範圍由資源字典的參照位置決定。

[樣式] 定義中,您需要 [TargetType] 屬性和一或多個 [Setter] 元素的集合。 TargetType 屬性是一個字串,會指定要套用樣式的 FrameworkElement 類型。 TargetType 值必須指定由 Windows 執行階段所定義的 FrameworkElement 衍生類型,或參考組件中可用的自訂類型。 如果您嘗試將樣式套用至控制項,且控制項的類型不符合您嘗試套用之樣式的 TargetType 屬性,就會發生例外狀況。

每個 Setter 元素都需要屬性。 這些屬性設定會指出設定所套用的控制項屬性,以及要為該屬性設定的值。 您可以使用屬性或屬性項目語法來設定 Setter.Value。 這裡的 XAML 會顯示套用至先前所顯示按鈕的樣式。 這個 XAML 的前兩個 Setter 元素使用屬性 (Attribute) 語法,而最後一個用於 BorderBrush 屬性的 Setter 則是使用屬性 (Property) 元素語法。 此範例不會使用 [x:Key attribute] 屬性,因此樣式會隱含地套用至按鈕。 下一節會說明隱含或明確套用樣式。

<Page.Resources>
    <Style TargetType="Button">
        <Setter Property="BorderThickness" Value="5" />
        <Setter Property="Foreground" Value="Black" />
        <Setter Property="BorderBrush" >
            <Setter.Value>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
    </Style>
</Page.Resources>

<StackPanel Orientation="Horizontal">
    <Button Content="Button"/>
    <Button Content="Button"/>
    <Button Content="Button"/>
</StackPanel>

套用隱含或明確樣式

如果您將樣式定義成資源,則將它套用至控制項的方式有兩種:

如果樣式內含 x:Key 屬性,則您必須對這種索引鍵樣式設定控制項的 Style 屬性,才能將該樣式套用至控制項。 相反地,沒有 x:Key 屬性的樣式會自動套用至其目標類型的每個控制項,否則不會有明確的樣式設定。

以下是示範隱含和明確樣式的兩個按鈕。

implicitly and explicitly styled buttons.

在這個範例中,第一個樣式具有 x:Key 屬性,其目標類型為 Button。 第一個按鈕的 [樣式] 屬性設定為此索引鍵,所以此樣式為明確套用。 第二種樣式是隱含套用至第二個按鈕,因為其目標類型是 [按鈕],而且該樣式並沒有 x:Key 屬性。

<Page.Resources>
    <Style x:Key="PurpleStyle" TargetType="Button">
        <Setter Property="FontFamily" Value="Segoe UI"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="Foreground" Value="Purple"/>
    </Style>

    <Style TargetType="Button">
        <Setter Property="FontFamily" Value="Segoe UI"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="RenderTransform">
            <Setter.Value>
                <RotateTransform Angle="25"/>
            </Setter.Value>
        </Setter>
        <Setter Property="BorderBrush" Value="Green"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="Foreground" Value="Green"/>
    </Style>
</Page.Resources>

<Grid x:Name="LayoutRoot">
    <Button Content="Button" Style="{StaticResource PurpleStyle}"/>
    <Button Content="Button"/>
</Grid>

使用基於樣式

為了使樣式更易於維護並最佳化樣式的重複使用,您可以建立從其他樣式繼承的樣式。 您可以使用 [BasedOn] 屬性來建立繼承的樣式。 繼承自其他樣式的樣式,必須以相同類型的控制項或衍生自基底樣式目標類型的控制項為目標。 例如,如果基礎樣式的目標是 ContentControl,則以此樣式為基礎樣式的目標可以是 ContentControl,或是 [按鈕][ScrollViewer] 這類衍生自 ContentControl 的類型。 如果在基於樣式中未設定值,則將從基本樣式中繼承該值。 若要從基底樣式變更值,基於樣式會覆寫該值。 在下一個範例中,ButtonCheckBox 的樣式是繼承自同一個基礎樣式。

styled buttons usign based-on styles.

基底樣式會以 ContentControl 為目標,並設定 [高度][寬度] 屬性。 以此樣式為基礎的樣式目標是 ContentControl 所衍生的 [核取方塊][按鈕]。 基於樣式會為 [BorderBrush][Foreground] 屬性設定不同的色彩。 (您通常不會在 CheckBox 周圍放置框線 。我們在這裡這樣做,以顯示樣式的效果。)

<Page.Resources>
    <Style x:Key="BasicStyle" TargetType="ContentControl">
        <Setter Property="Width" Value="130" />
        <Setter Property="Height" Value="30" />
    </Style>

    <Style x:Key="ButtonStyle" TargetType="Button"
           BasedOn="{StaticResource BasicStyle}">
        <Setter Property="BorderBrush" Value="Orange" />
        <Setter Property="BorderThickness" Value="2" />
        <Setter Property="Foreground" Value="Red" />
    </Style>

    <Style x:Key="CheckBoxStyle" TargetType="CheckBox"
           BasedOn="{StaticResource BasicStyle}">
        <Setter Property="BorderBrush" Value="Blue" />
        <Setter Property="BorderThickness" Value="2" />
        <Setter Property="Foreground" Value="Green" />
    </Style>
</Page.Resources>

<StackPanel>
    <Button Content="Button" Style="{StaticResource ButtonStyle}" Margin="0,10"/>
    <CheckBox Content="CheckBox" Style="{StaticResource CheckBoxStyle}"/>
</StackPanel>

使用工具輕鬆地處理樣式

將樣式套用至控制項的快速方法,是以滑鼠右鍵按一下 Microsoft Visual Studio XAML 設計介面上的控制項,然後選取 [編輯樣式][編輯範本] (視您按一下滑鼠右鍵的控制項而定)。 然後,您可以選取 [套用資源] 或選取 [建立空白] 來定義新的樣式,以套用現有的樣式。 如果您建立空白的樣式,您可以選擇在頁面、App.xaml 檔案或個別的資源字典中將其定義。

輕量化樣式

覆寫系統筆刷一般是在應用程式或頁面層級完成,而且在任一情況下,色彩覆寫都會影響參考該筆刷的所有控制項,而在 XAML 中,多個控制項可以參考相同的系統筆刷。

Screenshot of two buttons: one in its rest state and one with lightweight Styling applied.

<Page.Resources>
    <ResourceDictionary>
        <ResourceDictionary.ThemeDictionaries>
            <ResourceDictionary x:Key="Light">
                 <SolidColorBrush x:Key="ButtonBackground" Color="Transparent"/>
                 <SolidColorBrush x:Key="ButtonForeground" Color="MediumSlateBlue"/>
                 <SolidColorBrush x:Key="ButtonBorderBrush" Color="MediumSlateBlue"/>
            </ResourceDictionary>
        </ResourceDictionary.ThemeDictionaries>
    </ResourceDictionary>
</Page.Resources>

針對 PointerOver (滑鼠懸停在按鈕上)、PointerPressed (已叫用按鈕),或 [停用] (按鈕無法互動) 等狀態。 這些結束符號會附加至原始輕量化樣式名稱:ButtonBackgroundPointerOverButtonForegroundPressedButtonBorderBrushDisabled 等。同時修改這些筆刷,將確保您的控制項顏色與應用程式的主題一致。

將這些筆刷覆寫放在 App.Resources 層級,將會改變整個應用程式內的所有按鈕,而不是只改變單一頁面。

個別控制項樣式

在其他情況下,需要僅更改頁面上的單一控制項的外觀,而不更改該控制項的任何其他版本:

Screenshot of three styled buttons arranged stacked one on top of the other.

<CheckBox Content="Normal CheckBox" Margin="5"/>
<CheckBox Content="Special CheckBox" Margin="5">
    <CheckBox.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary x:Key="Light">
                    <SolidColorBrush x:Key="CheckBoxForegroundUnchecked"
                        Color="Purple"/>
                    <SolidColorBrush x:Key="CheckBoxForegroundChecked"
                        Color="Purple"/>
                    <SolidColorBrush x:Key="CheckBoxCheckGlyphForegroundChecked"
                        Color="White"/>
                    <SolidColorBrush x:Key="CheckBoxCheckBackgroundStrokeChecked"  
                        Color="Purple"/>
                    <SolidColorBrush x:Key="CheckBoxCheckBackgroundFillChecked"
                        Color="Purple"/>
                </ResourceDictionary>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </CheckBox.Resources>
</CheckBox>
<CheckBox Content="Normal CheckBox" Margin="5"/>

這只會影響該控制項存在之頁面上的一個「特殊核取方塊」。

自訂控制項

當您建置自訂控制項 (可能在視覺上和/或功能上與我們的內建控制項一致) 時,請考慮使用隱含樣式和輕量化樣式資源來定義您的自訂內容。 您可以直接使用資源,或為資源建立新的別名。

直接使用控制項資源

例如,如果您要寫入看起來像 [按鈕] 的控制項,您可以讓控制項直接參考按鈕資源,如下所示:

<Style TargetType="local:MyCustomControl">
  <Setter Property="Background" Value="{ThemeResource ButtonBackground}" />
  <Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}" />
</Style>

將控制項資源別名化為新名稱

或者,如果您喜歡建立自己的資源,則應該將這些自訂名稱別名為我們預設的輕量化樣式資源。

例如,自訂控制項的樣式可能有特殊的資源定義:

<Style TargetType="local:MyCustomControl">
  <Setter Property="Background" Value="{ThemeResource MyCustomControlBackground}" />
  <Setter Property="BorderBrush" Value="{ThemeResource MyCustomControlBorderBrush}"/>
</Style>

在您的「資源字典」或主要定義中,您會將輕量化樣式資源連結至自訂資源:

<ResourceDictionary.ThemeDictionaries>
    <ResourceDictionary x:Key="Default">
        <StaticResource x:Key="MyCustomControlBackground" ResourceKey="ButtonBackground" />
        <StaticResource x:Key="MyCustomControlBorderBrush" ResourceKey="ButtonBorderBrush" />
    </ResourceDictionary>        
    <ResourceDictionary x:Key="Light">
        <StaticResource x:Key="MyCustomControlBackground" ResourceKey="ButtonBackground" />
        <StaticResource x:Key="MyCustomControlBorderBrush" ResourceKey="ButtonBorderBrush" />
    </ResourceDictionary>
    <ResourceDictionary x:Key="HighContrast">
        <StaticResource x:Key="MyCustomControlBackground" ResourceKey="ButtonBackground" />
        <StaticResource x:Key="MyCustomControlBorderBrush" ResourceKey="ButtonBorderBrush" />
    </ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>

您必須使用重複三次的 ThemeDictionary,才能正確處理三個不同的主題變更 (DefaultLightHighContrast)。

警告

如果您將輕量化樣式資源指派給新的別名,而且也會重新定義輕量化樣式資源,且資源查找順序不正確,則您的自訂可能不會套用。 例如,如果您在找到 MyCustomControlBackground 之前搜尋的位置覆寫 ButtonBackground,則會遺漏覆寫。

避免重新設定控制項樣式

Windows UI 程式庫 2.2 或更新版本,包含 WinUI 和系統控制項的新樣式和範本。

保持最新視覺化樣式的最佳方式是使用最新的 WinUI 2 套件,並避免自訂樣式和範本 (也稱為重新範本化)。 樣式仍然是在應用程式的控制項之間,一致套用一組值的便捷方法。 這樣做時,請務必以我們最新的樣式為基礎。

對於使用 WinUI 樣式的系統控制項 (Windows.UI.Xaml.Controls 命名空間),請設定 BasedOn="{StaticResource Default<ControlName>Style}",其中 <ControlName> 是控制項的名稱。 例如:

<Style TargetType="TextBox" BasedOn="{StaticResource DefaultTextBoxStyle}">
    <Setter Property="Foreground" Value="Blue"/>
</Style>

針對 WinUI 2 控制項 (Microsoft.UI.Xaml.Controls 命名空間),預設樣式會在中繼資料中定義,因此請省略 BasedOn

衍生控制項

如果您從現有的 XAML 控制項衍生自訂控制項,則預設不會取得 WinUI 2 樣式。 若要套用 WinUI 2 樣式:

  • 建立新的樣式,並將其 TargetType 設訂為您的自訂控制項。
  • 將樣式基於您衍生自的控制項的預設樣式。

其中一個常見案例是從 ContentDialog 衍生新的控制項。 此範例示範如何建立套用 DefaultContentDialogStyle 至自訂對話方塊的新樣式。

<ContentDialog
    x:Class="ExampleApp.SignInContentDialog"
    ... >

    <ContentDialog.Resources>
        <Style TargetType="local:SignInContentDialog" BasedOn="{StaticResource DefaultContentDialogStyle}"/>
        ...
    </ContentDialog.Resources> 
    <!-- CONTENT -->
</ContentDialog>        

Template (範本) 屬性

樣式 Setter 可以用於 ControlTemplate 屬性,事實上,大多數的典型 XAML 樣式和應用程式 XAML 資源都是由此組成。 這部分內容將在控制項範本主題中深入討論。