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 中的資源。 如果資源是在不同的資源字典檔案中定義,則其範圍由資源字典的參照位置決定。

Style 定義中,您需要一個 TargetType 屬性以及包含一或多個 Setter 元素的集合。 TargetType 屬性是一個字串,會指定要套用樣式的 FrameworkElement 類型。 TargetType 值必須指定 Windows 執行階段定義的 FrameworkElement 衍生類型,或是可在參考組件中取得的自訂類型。 如果您嘗試將樣式套用到控制項,但控制項的類型不符合您嘗試套用之樣式的 TargetType 屬性,就會發生例外狀況。

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

<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。 第一個按鈕的 Style 屬性設為此索引鍵,所以是明確套用此樣式。 第二種樣式是以隱含方式套用至第二個按鈕,因為其目標類型是 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,或是 ButtonScrollViewer 這類衍生自 ContentControl 的類型。 如果根據樣式中沒有設定某個值,則該值就會繼承自基礎樣式。 若是變更基礎樣式的值,則根據樣式會覆寫該值。 在下一個範例中,ButtonCheckBox 的樣式是繼承自同一個基礎樣式。

styled buttons usign based-on styles.

基礎樣式的目標是 ContentControl,並設定 HeightWidth 屬性。 以此樣式為基礎的樣式目標是 ContentControl 所衍生的 CheckBoxButton。 根據樣式可為 BorderBrushForeground 屬性設定不同色彩。 (您通常不會在 CheckBox周圍放置框線。我們會在這裡顯示 style.) 的效果

<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 (叫用按鈕) 或 Disabled (按鈕無法互動) 之類的狀態。 下列結尾會附加到原始的輕量型樣式設定名稱︰ButtonBackgroundPointerOverButtonForegroundPointerPressedButtonBorderBrushDisabled 等。同時修改這些筆刷可確保您的控制項色彩和您的應用程式佈景主題一致。

將這些筆刷覆寫放在 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"/>

這只會影響該控制項存在的頁面上有一個「特殊 CheckBox」。

自訂控制項

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

直接使用控制資源

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

<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 重複三次的 ,才能正確處理三個不同的主題變更, Default (、 LightHighContrast) 。

警告

如果您將輕量型樣式資源指派給新的別名,而且也會重新定義輕量型樣式資源,則如果資源查閱的順序不正確,則可能不會套用自訂專案。 例如,如果您在找到之前 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 樣式:

  • 建立新的 Style ,並將其 TargetType 設為您的自訂控制項。
  • 根據您衍生自之控制項的預設樣式來建立樣式。

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

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

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

Template (範本) 屬性

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