Ресурсы темы XAML

Ресурсы темы в XAML — это набор ресурсов, которые применяют разные значения в зависимости от того, какая системная тема активна. Существует 3 темы, поддерживаемые платформой XAML: Light, Dark и HighContrast.

Предварительные требования. В этом разделе предполагается, что у вас есть ссылки на ресурсы ResourceDictionary и XAML.

Ресурсы темы v. статические ресурсы

Существует два расширения разметки XAML, которые могут ссылаться на ресурс XAML из существующего словаря ресурсов XAML: расширение разметки {StaticResource} и расширение разметки {ThemeResource}.

Оценка расширения разметки {ThemeResource} возникает при загрузке приложения и последующем каждом изменении темы во время выполнения. Обычно это результат изменения параметров устройства или программного изменения в приложении, которое изменяет текущую тему.

Напротив, расширение разметки {StaticResource} вычисляется только при первой загрузке XAML приложением. Он не обновляется. Он аналогичен поиску и замене в XAML фактическим значением среды выполнения при запуске приложения.

Ресурсы темы в структуре словаря ресурсов

Каждый ресурс темы является частью файла XAML fileresources.xaml. В целях разработки themeresources.xaml доступен в папке \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic из установки пакета SDK для Windows. Словари ресурсов в themeresources.xaml также воспроизводится в generic.xaml в том же каталоге.

Среда выполнения Windows не использует эти физические файлы для поиска во время выполнения. Именно поэтому они находятся в папке DesignTime, и по умолчанию они не копируются в приложения. Вместо этого эти словари ресурсов существуют в памяти как часть самого среда выполнения Windows, а ссылки на ресурсы XAML приложения на ресурсы темы (или системные ресурсы) разрешаются в среде выполнения.

Рекомендации по использованию пользовательских ресурсов темы

Следуйте данным рекомендациям, чтобы определить и использовать собственные настраиваемые ресурсы темы:

  • Укажите словари тем для "Light" и "Dark" в дополнение к словарю HighContrast. Хотя вы можете создать ResourceDictionary с параметром Default в качестве ключа, предпочтительнее быть явным и вместо этого использовать "Light", "Dark" и "HighContrast".

  • Используйте расширение разметки {ThemeResource} в: стили, наборы элементов управления, шаблоны элементов управления, методы задания свойств и анимации.

  • Не используйте расширение разметки {ThemeResource} в определениях ресурсов в словарях ThemeDictionaries. Вместо этого используйте расширение разметки {StaticResource}.

    ИСКЛЮЧЕНИЕ. Расширение разметки {ThemeResource} можно использовать для ссылки на ресурсы, которые не зависят от темы приложения в ThemeDictionaries. Примерами этих ресурсов являются ресурсы цвета акцента, такие как SystemAccentColorили системные цветовые ресурсы, которые обычно префиксируются с помощью SystemColor SystemColorButtonFaceColor.

Внимание

Если вы не следуйте этим рекомендациям, в приложении может появиться непредвиденное поведение, связанное с темами. Дополнительные сведения см. в разделе "Устранение неполадок с ресурсами темы".

Цветовая рампа XAML и кисти, зависящие от темы

Объединенный набор цветов для тем "Свет", "Темный" и "HighContrast" составляют цветовую рампу Windows в XAML. Следует ли изменить системные темы или применить тему к собственным элементам XAML, важно понять, как структурированы цветовые ресурсы.

Дополнительные сведения о том, как применять цвета в приложение Windows, см. в статье Цвета в приложениях Windows.

Цвета светлой и темной темы

Платформа XAML предоставляет набор именованных ресурсов Color со значениями, подобранными для тем Light и Dark. Для WinUI 2 ресурсы темы определяются в файле Xaml общих ресурсов темы. Имена цветов очень описательные для их предполагаемого использования, и для каждого ресурса Color есть соответствующий ресурс SolidColorBrush.

Совет

Визуальный обзор этих цветов см. в приложении коллекции WinUI 3: Colors

Приложение коллекции WinUI 3 включает интерактивные примеры большинства элементов управления, функций и функций WinUI 3. Получение приложения из Microsoft Store или получение исходного кода на GitHub

Цвета темы контрастности системы Windows

Помимо набора ресурсов, предоставляемых платформой XAML, существует набор значений цвета, производных от системной палитры Windows. Эти цвета не привязаны к среде выполнения Windows или приложениям Windows. Однако многие из ресурсов Brush XAML используют эти цвета, когда система работает (и приложение выполняется) с темой HighContrast. Платформа XAML предоставляет эти системные цвета в качестве ключевых ресурсов. Ключи соответствуют формату именования: SystemColor[name]Color

Дополнительные сведения о поддержке тем контрастности см. в разделе "Темы контрастности".

Цвет системного акцента

Помимо цветов темы контрастности системы, системный цвет акцента предоставляется в качестве специального ресурса цвета с помощью ключа SystemAccentColor. Во время выполнения этот ресурс получает цвет, указанный пользователем в качестве цвета акцента в параметрах персонализации Windows.

Примечание.

Хотя можно переопределить системные цветовые ресурсы, рекомендуется уважать выбор цвета пользователя, особенно для параметров контрастной темы.

Кисти, зависящие от темы

Ресурсы цвета, рассмотренные в предыдущих разделах, используются для определения свойства Color ресурсов SolidColorBrush в словарях ресурсов темы системы. Ресурсы кисти используются для применения цвета к элементам XAML.

Давайте рассмотрим, как значение цвета для этой кисти определяется во время выполнения. В словарях ресурсов Light и Dark эта кисть определяется следующим образом:

<SolidColorBrush x:Key="TextFillColorPrimaryBrush" Color="{StaticResource TextFillColorPrimary}"/>

В словаре ресурсов HighContrast эта кисть определяется следующим образом:

<SolidColorBrush x:Key="TextFillColorPrimaryBrush" Color="{ThemeResource SystemColorWindowTextColor}"/>

Если эта кисть применяется к элементу XAML, его цвет определяется во время выполнения текущей темой, как показано в этой таблице.

Theme Цветовой ресурс Значение среды выполнения
Светлый TextFillColorPrimary #E4000000
Темный TextFillColorPrimary #FFFFFFFF
HighContrast SystemColorWindowTextColor Цвет, указанный в параметрах текста.

Пандус типа XAML

Файл themeresources.xaml определяет несколько ресурсов, определяющих стиль Style, который можно применить к контейнерам текста в вашем пользовательском интерфейсе, в частности для TextBlock или RichTextBlock. Это неявные стили по умолчанию. Они предоставляются для упрощения создания определений пользовательского интерфейса XAML, которые соответствуют пандусу типа Windows, документированному в рекомендациях по шрифтам.

Эти стили предназначены для текстовых атрибутов, которые необходимо применить ко всему текстовому контейнеру. Если вам нужно, чтобы стили применялись только к отдельным частям текста, следует задать атрибуты для элементов текста в контейнере, например Run в TextBlock.Inlines или Paragraph в RichTextBlock.Blocks.

При применении к TextBlock стили выглядят таким образом:

text block styles

Стиль Вес Размер
Заголовок Обычное 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 см. в статье WinUI на сайте GitHub:

Совет

Визуальный обзор этих стилей см. в приложении коллекции WinUI 3: Typeography

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 упрощает настройку атрибутов для отдельных текстовых элементов. Кроме того, параметр TextBlock.Text, использующий свойство XAML-содержимого, описывает ситуацию, где отсутствуют элементы текста, к которым нужно применить стиль, поэтому стиль необходимо применить к контейнеру. Это не является проблемой для RichTextBlock, так как его текстовое содержимое всегда должно находиться в определенных элементах текста, таких как Paragraph. Именно в них вы можете применить стили XAML для заголовка страницы, подзаголовка страницы и аналогичных определений из таблицы шрифтов.

Другие стили именованных именованных элементов

Существует дополнительный набор определений Style с ключами, которые можно применить, чтобы стиль кнопки Button отличался от стандартного неявного стиля.

TargetType: Button

Этот стиль Style предоставляет полный шаблон для элемента управления Button, который может использоваться как кнопка навигации "Назад" для приложения навигации. Размеры по умолчанию — 40 x 40 пикселей. Для настройки стиля можно либо явным образом задать Height, Width, FontSize и другие свойства кнопки Button, либо создать производный стиль, используя BasedOn.

Вот пример кнопки Button с примененным к ней ресурсом NavigationBackButtonNormalStyle.

<Button Style="{StaticResource NavigationBackButtonNormalStyle}" />

Он будет выглядеть примерно так:

A button styled as a back button

TargetType: Button

Этот стиль Style предоставляет полный шаблон для элемента управления Button, который может использоваться как кнопка навигации "Назад" для приложения навигации. Он похож на стиль NavigationBackButtonNormalStyle, но его размер составляет 30 x 30 пикселей.

Вот пример кнопки Button с примененным к ней ресурсом NavigationBackButtonSmallStyle.

<Button Style="{StaticResource NavigationBackButtonSmallStyle}" />

Устранение неполадок с ресурсами темы

Если вы не следуйте рекомендациям по использованию ресурсов темы, в приложении может появиться непредвиденное поведение, связанное с темами.

Например, при открытии всплывающего меню с светлой темой части вашего темного приложения также изменяются, как если бы они были в светлой теме. Или если перейти к светло-тематическим страницам, а затем вернуться, исходная темная тематические страницы (или части) теперь выглядит, как будто она находится в светлой теме.

Как правило, эти типы проблем возникают при предоставлении темы по умолчанию и темы HighContrast для поддержки сценариев высокой контрастности, а затем используются темы Light и Dark в разных частях приложения.

Например, рассмотрим это определение словаря тем:

<!-- 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. Если у вас есть 2 элемента в вложенных деревах XAML с различными темами, ссылающимися на один ресурс кисти, то при использовании платформы выполняется пошаговое обновление всех вложенных деревьев для обновления выражений расширения разметки {ThemeResource}, изменения в общем ресурсе кисти отражаются в другом дочернем дереве, который не является вашим предполагаемым результатом.

Чтобы устранить эту проблему, замените словарь по умолчанию отдельными словарями тем для тем "Light" и "Dark" в дополнение к 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}, он вычисляется повторно.

На этом этапе платформа, как представляется, загрязнила словарь тем, так как теперь он имеет ресурс из одного словаря, который имеет свой цветной набор из другого словаря.

Чтобы устранить эту проблему, используйте расширение разметки {StaticResource} вместо расширения разметки {ThemeResource}. При применении рекомендаций словари тем выглядят следующим образом:

<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}.