XAML 佈景主題資源
XAML中的主題資源是一組資源,根據啟用的系統主題,套用不同的值。 XAML 架構支援 3 個主題:[淺色]、[深色] 和 [HighContrast]。
必要條件:本主題假設您已閱讀 ResourceDictionary 和 XAML 資源參考。
主題資源與靜態資源
有兩個 XAML 標記延伸可以從現有的 XAML 資源字典參考 XAML 資源:{StaticResource} 標記延伸 和 {ThemeResource} 標記延伸。
當應用程式載入,並在執行階段每次變更主題時,就會發生 {ThemeResource} 標記延伸的評估。 這通常是使用者變更其裝置設定的結果,或是從改變其目前主題的應用程式內以程式設計方式變更的結果。
相反地,只有在應用程式第一次載入 XAML 時,才會評估 {StaticResource} 標記延伸。 這不會更新。 它類似於在 XAML 中尋找並替換為應用程式啟動時的實際執行階段值。
資源字典結構中的佈景主題資源
每個主題資源都是 XAML 檔案 themeresources.xaml 的一部分。 基於設計目的,Windows 軟體開發套件 (SDK) 安裝的 \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic 資料夾中會提供 themeresources.xaml。 themeresources.xaml 中的資源字典也會在同目錄中的 generic.xaml 中重現。
Windows 執行階段不會使用這些實體檔案進行執行階段查詢。 這就是為什麼它們特別位於 [DesignTime] 資料夾中,而且預設不會複製到應用程式。 相反地,這些資源字典會存在於記憶體中,做為「Windows 執行階段」本身的一部分,而應用程式對主題資源 (或系統資源) 的 XAML 資源參考會在執行階段解析到該處。
自訂佈景主題資源的指導方針
當您定義並取用自己的自訂佈景主題資源時,請遵循下列指導方針:
除了您的 [HighContrast] 字典之外,請為 [淺色] 和 [深色] 指定主題字典。 雖然您可以使用 [預設] 作為索引鍵來建立 [ResourceDictionary],但建議您明確使用 [淺色]、[深色] 和 [HighContrast]。
使用 {ThemeResource} 標記延伸:樣式、Setter、控制項範本、屬性 setter 和動畫。
不要在 ThemeDictionaries 內的資源定義中使用 {ThemeResource} 標記延伸。 請改用 {StaticResource} 標記延伸 。
例外狀況:您可以在 [ThemeDictionaries] 中使用 {ThemeResource} 標記延伸參考與應用程式主題無關的資源。 這些資源的範例包括的輔色資源,例如
SystemAccentColor
, 或系統色彩資源,通常前面會加上 “SystemColor” ,例如SystemColorButtonFaceColor
。
警告
如果未遵循這些指導方針,您可能會在您的應用程式中看到與主題相關的非預期行為。 如需更多資訊,請參閱疑難排解主題資源一節。
XAML 色彩坡形和主題相依筆刷
[淺色]、[深色] 和 [HighContrast] 主題的一組組合色彩,組成 XAML 中的 Windows 色彩坡形。 無論您是要修改系統主題,還是將主題套用至自己的 XAML 元素,都必須了解色彩資源的結構化方式。
如需有關如何在 Windows 應用程式中套用色彩的詳細資訊,請參閱 Windows 應用程式中的色彩。
淺色和深色主題色彩
XAML 架構提供一組名為 [色彩] 的資源,其中包含針對 [淺色] 和 [深色] 主題量身打造的值。 針對 WinUI 2,主題資源定義於通用主題資源 Xaml 檔案。 色彩名稱清晰描述其預定的使用方式,而且每個 [色彩] 資源都有對應的 SolidColorBrush 資源。
提示
如需這些色彩的視覺概觀,請參閱 WinUI 3 資源庫應用程式:色彩
WinUI 3 資源庫應用程式包含大多數 WinUI 3 控制項和功能的互動式範例。 從 Microsoft Store 取得應用程式,或在 GitHub 上取得原始程式碼
Windows 系統對比主題色彩
除了 XAML 架構所提供的一組資源之外,還有一組衍生自 Windows 系統調色盤的色彩值。 這些色彩並不是 Windows 執行階段或 Windows 應用程式專用的。 不過,當系統運作時,許多 XAML 筆刷資源會使用 [HighContrast] 主題來取用這些色彩。 XAML 架構會提供這些全系統色彩作為索引鍵資源。 索引鍵會遵循命名格式:SystemColor[name]Color
。
如需支援對比主題的詳細資訊,請參閱對比主題。
系統輔色
除了系統對比主題色彩之外,系統輔色也會使用索引鍵 SystemAccentColor
作為特殊色彩資源提供。 在執行階段,此資源會取得使用者在 Windows 個人化設定中指定為輔色的色彩。
注意
雖然可以覆寫系統色彩資源,但是最佳作法還是尊重使用者的色彩選擇,特別是針對對比主題設定。
佈景主題相依筆刷
前述各節中顯示的色彩資源可用來設定系統佈景主題資源字典中 SolidColorBrush 資源的 [色彩] 屬性。 您可以使用筆刷資源,將色彩套用到 XAML 元素。
讓我們看看此筆刷的色彩值在執行階段如何決定。 在 [淺色] 和 [深色] 資源字典中,此筆刷的定義如下:
<SolidColorBrush x:Key="TextFillColorPrimaryBrush" Color="{StaticResource TextFillColorPrimary}"/>
在 [HighContrast] 資源字典中,此筆刷的定義如下:
<SolidColorBrush x:Key="TextFillColorPrimaryBrush" Color="{ThemeResource SystemColorWindowTextColor}"/>
當此筆刷套用至 XAML 元素時,其色彩會在執行階段由目前的主題決定,如此資料表所示。
佈景主題 | 色彩資源 | 執行階段值 |
---|---|---|
淺色 | TextFillColorPrimary | #E4000000 |
深色 | TextFillColorPrimary | #FFFFFFFF |
HighContrast | SystemColorWindowTextColor | [文字] 設定中指定的色彩。 |
XAML 類型坡形
themeresources.xaml 檔案會定義數個資源,這些資源定義您可以套用至 UI 中的文字容器的 [樣式],特別是針對 [TextBlock] 或 [RichTextBlock]。 這些不是預設的隱含樣式。 它們提供的是為了讓您更容易地在符合字體指南中所記錄的 Windows 字體坡型的 XAML UI 定義。
這些樣式是用於您想要套用到整個文字容器的文字屬性。 如果只想將樣式套用到文字的區段,請針對容器內的文字元素設定屬性,例如,TextBlock.Inlines 中的 [執行] 或 RichTextBlock.Blocks 中的 [段落]。
當套用至 TextBlock 時樣式看起來像這樣:
樣式 | Weight | 大小 |
---|---|---|
標題 | 一般 | 12 |
本文 | 一般 | 14 |
本文強式 | 半粗體 | 14 |
本文大尺寸 | 一般 | 18 |
子標題 | 半粗體 | 20 |
標題 | 半粗體 | 28 |
標題大尺寸 | 半粗體 | 40 |
顯示器 | 半粗體 | 68 |
<TextBlock Text="Caption" Style="{StaticResource CaptionTextBlockStyle}"/>
<TextBlock Text="Body" Style="{StaticResource BodyTextBlockStyle}"/>
<TextBlock Text="Body Strong" Style="{StaticResource BodyStrongTextBlockStyle}"/>
<TextBlock Text="Body Large" Style="{StaticResource BodyLargeTextBlockStyle}"/>
<TextBlock Text="Subtitle" Style="{StaticResource SubtitleTextBlockStyle}"/>
<TextBlock Text="Title" Style="{StaticResource TitleTextBlockStyle}"/>
<TextBlock Text="Title Large" Style="{StaticResource TitleLargeTextBlockStyle}"/>
<TextBlock Text="Display" Style="{StaticResource DisplayTextBlockStyle}"/>
如需有關如何在您的應用程式中使用 Windows 字體坡形的指引,請參閱 Windows 應用程式中的印刷樣式。
如需 XAML 樣式的詳細資訊,請參閱 GitHub 上的 WinUI:
提示
如需這些樣式的視覺概觀,請參閱 WinUI 3 資源庫應用程式:印刷樣式
BaseRichTextBlockStyle
TargetType: RichTextBlock
提供所有其他 RichTextBlock 容器樣式的一般屬性。
<!-- Usage -->
<RichTextBlock Style="{StaticResource BaseRichTextBlockStyle}">
<Paragraph>Rich text.</Paragraph>
</RichTextBlock>
<!-- Style definition -->
<Style x:Key="BaseRichTextBlockStyle" TargetType="RichTextBlock">
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="TextTrimming" Value="None"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="LineStackingStrategy" Value="MaxHeight"/>
<Setter Property="TextLineBounds" Value="Full"/>
<Setter Property="OpticalMarginAlignment" Value="TrimSideBearings"/>
</Style>
BodyRichTextBlockStyle
<!-- Usage -->
<RichTextBlock Style="{StaticResource BodyRichTextBlockStyle}">
<Paragraph>Rich text.</Paragraph>
</RichTextBlock>
<!-- Style definition -->
<Style x:Key="BodyRichTextBlockStyle" TargetType="RichTextBlock" BasedOn="{StaticResource BaseRichTextBlockStyle}">
<Setter Property="FontWeight" Value="Normal"/>
</Style>
附註:RichTextBlock 樣式並沒有 TextBlock 擁有的所有文字坡形樣式,主要是因為 RichTextBlock 的區塊型文件物件模型,讓您能夠更容易針對個別的文字元素設定屬性。 此外,使用 XAML 內容屬性設定 TextBlock.Text,也會導致沒有要文字元素可供樣式化,因此您必須對容器進行樣式化。 這對 RichTextBlock 來說並不是問題,因為它的文字內容一律必須位於特定的文字元素 (例如 Paragraph) 中,這是您可能為頁首、子頁首及類似文字坡形定義套用 XAML 樣式的地方。
其他具名樣式
有一組額外的索引鍵 [樣式] 定義,您可以套用至設定[按鈕] 的樣式,與其預設的隱含樣式不同。
NavigationBackButtonNormalStyle
TargetType:[按鈕]
這個 [樣式] 提供了一個完整的 [按鈕] 範本,可以作為瀏覽應用程式的返回按鈕。 預設尺寸為 40 x 40 像素。 若要量身打造樣式,您可以在 [按鈕] 上明確設定 [高度]、[寬度]、[FontSize] 及其他屬性,或者使用 [BasedOn] 建立衍生的樣式。
以下是已套用 NavigationBackButtonNormalStyle 資源的 [按鈕]。
<Button Style="{StaticResource NavigationBackButtonNormalStyle}" />
畫面顯示為這樣:
NavigationBackButtonSmallStyle
TargetType:[按鈕]
這個 [樣式] 提供了一個完整的 [按鈕] 範本,可以作為瀏覽應用程式的返回按鈕。 與 NavigationBackButtonNormalStyle 類似,但尺寸是 30 x 30 像素。
以下是已套用 NavigationBackButtonSmallStyle 資源的 [按鈕]。
<Button Style="{StaticResource NavigationBackButtonSmallStyle}" />
疑難排解主題資源
如果未遵循使用主題資源的指導方針,您可能會在您的應用程式中看到與主題相關的非預期行為。
例如,當您開啟淺色主題飛出視窗時,深色主題應用程式的部分也會變更,就像它們位於淺色主題中一樣。 或者,如果您瀏覽至淺色主題頁面,然後往回瀏覽,原始深色主題頁面 (或部分頁面) 現在看起來就像是在淺色主題中。
通常,當您提供 [預設] 主題和 [高對比度] 主題以支援高對比度案例時,並在應用程式的不同部分使用 [淺色] 和 [深色] 主題時,就會出現這類問題。
例如,請考慮此主題字典定義:
<!-- DO NOT USE. THIS XAML DEMONSTRATES AN ERROR. -->
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="myBrush" Color="{ThemeResource ControlFillColorDefault}"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="myBrush" Color="{ThemeResource SystemColorButtonFaceColor}"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
直覺上,這看起來正確。 在高對比度模式下,您想要變更 myBrush
指向的色彩,但在非高對比度模式下,您依賴於 {ThemeResource} 標記延伸,以確保 myBrush
指向您主題的正確色彩。 如果您的應用程式從未在其視覺化樹狀結構中的元素上設定 FrameworkElement.RequestedTheme,這通常會如預期般運作。 然而,一旦開始重新設計視覺化樹狀結構的不同部分,您的應用程式就會遇到問題。
問題出現在於當筆刷是共用資源時,與大多數其他 XAML 類型不同。 如果您的 XAML 樹狀子目錄中有 2 個具有不同主題的元素但參考相同筆刷資源,則當架構逐步執行每個樹狀子目錄架構以更新其 {ThemeResource} 標記延伸 表達式時,共用筆刷資源的變更會反映在其他樹狀子目錄中,這不是您的預期結果。
若要修正此問題,除了 [HighContrast] 之外,請將 [預設] 字典取代為 [淺色] 和 [深色] 主題的個別主題字典:
<!-- DO NOT USE. THIS XAML DEMONSTRATES AN ERROR. -->
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="myBrush" Color="{ThemeResource ControlFillColorDefault}"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="myBrush" Color="{ThemeResource ControlFillColorDefault}"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="myBrush" Color="{ThemeResource SystemColorButtonFaceColor}"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
不過,如果在 [Foreground] 等繼承屬性中參考這些資源中的任何一項,仍會發生問題。 您的自訂控制項範本可能會使用 {ThemeResource} 標記延伸 來指定元素的前景色彩,但是當架構將繼承的值傳播至子元素時,它會提供 {ThemeResource} 標記延伸表達式所解析之資源的直接參考。 當架構在引導控制項的視覺化樹狀結構時處理主題變更時,這會導致問題。 它會重新評估 {ThemeResource} 標記延伸表達式以取得新的筆刷資源,但尚未將此參考傳播到控制項的子系;這會在稍後發生,例如在下一個測量傳遞期間。
因此,在逐步執行控制項視覺化樹狀結構以響應主題變更之後,架構會逐步引導子系並更新在其屬性上設定的任何 {ThemeResource} 標記延伸 表達式,或在其屬性上設定的物件。 這是發生問題的位置;架構會逐步解說筆刷資源,因為它使用 {ThemeResource} 標記延伸來指定其色彩,因此會重新評估。
到目前為止,架構會顯示為已干擾了您的佈景主題字典,因為它現在擁有來自某一個字典的資源,而其色彩是從其他字典設定的。
若要解決此問題,請不要使用 {ThemeResource} 標記延伸,改用 {StaticResource} 標記延伸。 套用指導方針之後,佈景主題字典看起來像這樣:
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="myBrush" Color="{StaticResource ControlFillColorDefault}"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="myBrush" Color="{StaticResource ControlFillColorDefault}"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="myBrush" Color="{ThemeResource SystemColorButtonFaceColor}"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
請注意,{ThemeResource} 標記延伸仍會在 [HighContrast] 字典中使用,而不是 {StaticResource} 標記延伸。 這種情況屬於指導方針稍早指定的例外狀況。 大部分用於 [HighContrast] 主題的筆刷值,都是使用由系統全域控制的色彩選擇,但公開給 XAML 作為特別命名的資源 (名稱前面中加上 'SystemColor')。 系統可讓使用者透過 [輕鬆存取中心] 來設定應該用於其對比主題設定的特定色彩。 這些色彩選項會套用至特別命名的資源。 XAML 架構會使用相同的主題變更事件,在偵測到系統層級變更時,也會更新這些筆刷。 這就是為什麼在這裡使用 {ThemeResource} 標記延伸的原因。