Ressources de thème XAML

Les ressources de thème de XAML sont un ensemble de ressources qui s’appliquent à différentes valeurs en fonction desquelles le thème du système est actif. Il existe 3 thèmes pris en charge par l’infrastructure XAML : « Light », « Dark » et « HighContrast ».

Conditions préalables : cette rubrique suppose que vous avez lu Références aux ressources ResourceDictionary et XAML.

Ressources de thème et ressources statiques

Deux extensions de balisage XAML peuvent référencer une ressource XAML d’un dictionnaire de ressources XAML existant : extension de balisage {StaticResource} et extension de balisage {ThemeResource}.

L’évaluation d’une extension de balisage {ThemeResource} se produit lors du chargement de l’application et à chaque changement de thème pendant l’exécution. Cela est notamment le cas lorsque l’utilisateur modifie les paramètres de son appareil ou lorsqu’un programme apporte à l’application un changement qui modifie son thème actuel.

En revanche, pour une extension de balisage {StaticResource}, une évaluation se produit uniquement lors du premier chargement du code XAML par l’application. Il n’y a aucune mise à jour. Le processus est similaire à une opération de type rechercher-remplacer dans votre code XAML avec la valeur d’exécution réelle au démarrage de l’application.

Ressources de thème dans la structure du dictionnaire de ressources

Chaque ressource de thème fait partie du fichier XAML themeresources.xaml. Pour la conception, themeresources.xaml est disponible dans le dossier \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<Version du SDK>\Generic d’une installation du SDK Windows. Les dictionnaires de ressources dans themeresources.xaml sont également reproduits dans generic.xaml dans le même répertoire.

Windows Runtime n’utilise pas ces fichiers physiques pour la recherche du runtime. C’est pourquoi ils se trouvent spécifiquement dans un dossier DesignTime et ne sont pas copiés dans les applications par défaut. À la place, ces dictionnaires de ressources existent en mémoire dans Windows Runtime proprement dit, et les références des ressources XAML de votre application aux ressources de thème (ou ressources système) sont résolues ici lors de l’exécution.

Recommandations pour les ressources de thème personnalisées

Respectez ces recommandations quand vous définissez et que vous consommez vos propres ressources de thème personnalisées :

  • Spécifiez des dictionnaires pour les thèmes « Light » et « Dark », en plus de votre dictionnaire « HighContrast ». Bien que vous puissiez créer un élément ResourceDictionary avec la clé « Default », nous vous recommandons d’être explicite et d’utiliser « Light », « Dark » et « HighContrast ».

  • Utilisez l’extension de balisage {ThemeResource} dans : styles, setters, modèles de contrôle, setters de propriété et animations.

  • N’utilisez pas l’extension de balisage {ThemeResource} dans les définitions de ressources de votre ThemeDictionaries. Utilisez plutôt l’extension de balisage {StaticResource}.

    Exception : vous pouvez utiliser l’extension de balisage {ThemeResource} pour référencer les ressources indépendantes du thème de l’application dans votre ThemeDictionaries. Il peut s’agir par exemple des ressources de couleur d’accentuation comme SystemAccentColor, ou des ressources de couleur système, qui présentent généralement le préfixe SystemColor, comme SystemColorButtonFaceColor.

Attention

Si vous ne suivez pas ces recommandations, vous constaterez peut-être un comportement inattendu lié aux thèmes dans votre application. Pour plus d’informations, voir la section Résolution des problèmes de ressources de thème.

Gamme de couleurs de code XAML et pinceaux dépendants du thème

L’ensemble des couleurs pour les thèmes « Light », « Dark » et « HighContrast » constitue la gamme de couleurs Windows du code XAML. Que vous souhaitiez modifier les thèmes système ou appliquer un thème à vos propres éléments XAML, il est important de comprendre comment les ressources de couleur sont structurées.

Pour plus d’informations sur la façon d’appliquer la couleur dans votre application Windows, consultez Couleur dans les applications Windows.

Couleurs des thèmes Light et Dark

L’infrastructure XAML fournit un ensemble de ressources Color nommées, avec des valeurs adaptées aux thèmes « Light » et « Dark ». Pour WinUI 2, les ressources de thème sont définies dans le fichier Xaml des ressources de thème communes. Les noms de couleurs sont très descriptifs de leur utilisation prévue, et il existe une ressource SolidColorBrush correspondante pour chaque ressource Color.

Conseil

Pour obtenir une vue d’ensemble visuelle de ces couleurs, consultez l’application galerie WinUI 3 : Couleurs

L’application WinUI 3 Gallery comprend des exemples interactifs de la plupart des contrôles et des fonctionnalités WinUI 3. Procurez-vous l’application sur la Boutique Microsoft ou le code source sur GitHub.

Couleurs du thème de contraste du système Windows

Outre l’ensemble des ressources fournies par l’infrastructure XAML, il existe un ensemble de valeurs de couleur dérivé de la palette du système Windows. Ces couleurs ne sont pas propres aux applications Windows Runtime ou aux applications Windows. Toutefois, la majeure partie des ressources Brush XAML utilisent ces couleurs lorsque le système fonctionne (et lorsque l’application est en cours d’exécution) avec le thème « HighContrast ». L’infrastructure XAML fournit ces couleurs système en tant que ressources à clé. Les clés respectent le format d’attribution de noms : SystemColor[name]Color.

Pour plus d’informations sur la prise en charge des thèmes de contraste, consultez Thèmes de contraste.

Couleur d’accentuation système

En plus des couleurs de thème à contraste du système, la couleur d’accentuation système est fournie comme ressource spéciale de couleur à l’aide de la clé SystemAccentColor. Au moment de l’exécution, cette ressource récupère la couleur que l’utilisateur a indiquée comme couleur d’accentuation dans les paramètres de personnalisation de Windows.

Remarque

Bien qu’il soit possible de remplacer les ressources de couleur système, il est cependant recommandé de respecter les couleurs choisies par l’utilisateur, en particulier pour les paramètres de thème à contraste.

Pinceaux dépendants du thème

Les ressources de couleur indiquées dans les sections précédentes sont utilisées pour définir la propriété Color des ressources SolidColorBrush dans les dictionnaires de ressources de thème du système. Les ressources de pinceau permettent d’appliquer la couleur à des éléments XAML.

Examinons à présent comment la valeur de couleur de ce pinceau est déterminée au moment de l’exécution. Dans les dictionnaires de ressources « Light » et « Dark », ce pinceau est défini comme ceci :

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

Dans le dictionnaire de ressources « HighContrast », ce pinceau est défini comme ceci :

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

Lorsque ce pinceau est appliqué à un élément XAML, sa couleur est déterminée au moment de l’exécution par le thème actuel, comme indiqué dans le tableau suivant.

Thème Ressources de couleur Valeur d’exécution
Clair TextFillColorPrimary #E4000000
Foncé TextFillColorPrimary #FFFFFFFF
HighContrast SystemColorWindowTextColor Couleur spécifiée dans les paramètres de texte.

Gamme de type XAML

Le fichier themeresources.xaml définit plusieurs ressources, qui définissent elles-mêmes un Style que vous pouvez appliquer à des conteneurs de texte dans votre interface utilisateur, plus spécifiquement pour TextBlock ou RichTextBlock. Il ne s’agit pas des styles implicites par défaut. Ils sont fournis pour faciliter la création de définitions XAML d’interface utilisateur qui correspondent à la gamme de type Windows explicitée dans Recommandations en matière de polices.

Ces styles concernent les attributs de texte à appliquer à l’ensemble du conteneur de texte. Si vous souhaitez appliquer des styles uniquement à certaines parties du texte, définissez des attributs sur les éléments de texte dans le conteneur, par exemple sur Run dans TextBlock.Inlines ou sur Paragraph dans RichTextBlock.Blocks.

Les styles ressemblent à ceci quand ils sont appliqués à un élément TextBlock :

text block styles

Style Poids Taille
Caption Regular 12
Corps Regular 14
Corps fort Semibold 14
Corps grand Regular 18
Subtitle Semibold 20
Titre Semibold 28
Titre grand Semibold 40
Display Semibold 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}"/>

Pour de l’aide sur l’utilisation de la gamme de caractères Windows dans votre application, consultez Typographie dans les applications Windows.

Pour plus d’informations sur les styles XAML, consultez WinUI sur GitHub :

Conseil

Pour obtenir une vue d'ensemble visuelle de ces styles, consultez l’application galerie WinUI 3 : Typographie

BaseRichTextBlockStyle

TargetType : RichTextBlock

Fournit les propriétés communes à tous les autres styles de conteneur 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>

Remarque : Les styles RichTextBlock n’ont pas tous les styles de gamme de texte de TextBlock, principalement car il est plus facile de définir des attributs sur les éléments de texte individuels avec le modèle d’objet de document basé sur des blocs pour RichTextBlock. Par ailleurs, si vous définissez TextBlock.Text à l’aide de la propriété de contenu XAML, vous ne pouvez pas appliquer de style à un élément de texte, ce qui vous oblige à appliquer un style au conteneur. Ceci ne constitue pas un problème pour RichTextBlock, car son contenu de texte doit toujours figurer dans des éléments de texte spécifiques comme Paragraph, c’est-à-dire l’emplacement où vous pouvez définir des styles XAML pour un en-tête de page, un sous-en-tête de page et des définitions de gamme de texte semblables.

Divers styles nommés

Il existe un ensemble supplémentaire de définitions Style à clé que vous pouvez appliquer pour donner à un Button un style autre que le style implicite par défaut.

TargetType : Button

Ce Style fournit un modèle complet pour un Button qui peut servir de bouton de navigation Précédent pour une application de navigation. Les dimensions par défaut sont de 40 × 40 pixels. Pour adapter le style, vous pouvez définir explicitement Height, Width, FontSize et d’autres propriétés sur votre Button, ou créer un style dérivé à l’aide de BasedOn.

Voici un Button auquel la ressource NavigationBackButtonNormalStyle est appliquée.

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

Elle se présente comme suit :

A button styled as a back button

TargetType : Button

Ce Style fournit un modèle complet pour un Button qui peut servir de bouton de navigation Précédent pour une application de navigation. Il est similaire à NavigationBackButtonNormalStyle, mais les dimensions sont de 30 x 30 pixels.

Voici un Button auquel la ressource NavigationBackButtonSmallStyle est appliquée.

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

Résolution des problèmes liés aux ressources de thème

Si vous ne suivez pas les recommandations pour l’utilisation de ressources de thème, vous constaterez peut-être un comportement inattendu lié aux thèmes dans votre application.

Par exemple, lorsque vous ouvrez un menu volant sur le thème clair, certaines parties de votre application sur le thème foncé changent également, comme si elles faisaient partie du thème clair. Ou, si vous naviguez vers une page sur le thème clair puis revenez en arrière, la page d’origine sur le thème foncé (ou certaines parties de cette page) se présente comme si elle était soumise au thème clair.

En règle générale, ces types de problèmes se produisent lorsque vous indiquez un thème « Default » et un thème « HighContrast » pour prendre en charge les scénarios à contraste élevé, puis utilisez les thèmes « Light » et « Dark » dans différentes parties de votre application.

Prenons l’exemple de cette définition de dictionnaire de thème :

<!-- 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>

Au premier abord, elle semble correcte. Vous souhaitez modifier la couleur vers laquelle pointe myBrush lorsque vous utilisez le contraste élevé, mais lorsque vous n’êtes pas en contraste élevé, vous vous appuyez sur l’extension de balisage {ThemeResource} pour vous assurer que myBrush pointe vers la bonne couleur pour votre thème. Si votre application n’a jamais d’ensemble FrameworkElement.RequestedTheme sur les éléments au sein de son arborescence visuelle, elle fonctionne généralement comme prévu. Toutefois, vous rencontrez des problèmes avec votre application dès que vous commencez à modifier le thème de différentes parties de votre arborescence visuelle.

Ce problème est dû au fait que les pinceaux sont des ressources partagées, contrairement à la plupart des autres types XAML. Si vous avez 2 éléments dans des sous-arborescences XAML avec différents thèmes qui font référence à la même ressource de pinceau, lorsque l’infrastructure parcourt chaque sous-arborescence pour mettre à jour les expressions d’extension de balisage {ThemeResource}, les modifications apportées à la ressource de pinceau partagée sont reflétées dans l’autre sous-arborescence, ce qui n’est pas le résultat souhaité.

Pour résoudre ce problème, remplacez le dictionnaire « Default » par des dictionnaires de thème distincts pour les thèmes « Light » et « Dark », en plus du thème « 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>

Toutefois, vous rencontrerez toujours des problèmes si l’une de ces ressources est référencée dans les propriétés héritées comme Foreground. Votre modèle de contrôle personnalisé peut spécifier la couleur de premier plan d’un élément à l’aide de l’extension de balisage {ThemeResource}, mais lorsque l’infrastructure propage la valeur héritée aux éléments enfants, elle fournit une référence directe à la ressource qui a été résolue par l’expression d’extension de balisage {ThemeResource}. Cela crée des problèmes lorsque l’infrastructure traite les modifications du thème au fur et à mesure qu’elle parcourt l’arborescence visuelle de votre contrôle. Elle évalue de nouveau l’expression d’extension de balisage {ThemeResource} afin d’obtenir une nouvelle ressource de pinceau, mais ne propage pas encore cette référence vers les enfants de votre contrôle ; cela se produit plus tard, par exemple pendant la passe de mesure suivante.

Par conséquent, après avoir parcouru l’arborescence visuelle du contrôle suite à un changement de thème, l’infrastructure parcourt les enfants et met à jour les expressions d’extension de balisage {ThemeResource} définies sur chacun d’eux, ou sur les objets définis à partir de leurs propriétés. C’est à ce moment que le problème survient ; l’infrastructure parcourt la ressource de pinceau et, dans la mesure où elle spécifie sa couleur à l’aide d’une extension de balisage {ThemeResource}, une réévaluation est effectuée.

À ce stade, l’infrastructure semble avoir pollué votre dictionnaire de thèmes : il inclut désormais une ressource d’un dictionnaire dont la couleur est définie à partir d’un autre dictionnaire.

Pour résoudre ce problème, utilisez l’extension de balisage {StaticResource} à la place de l’extension de balisage {ThemeResource}. Si vous appliquez correctement les recommandations, les dictionnaires de thèmes se présentent ainsi :

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

Notez que l’extension de balisage {ThemeResource} est toujours utilisée à la place de l’extension de balisage {StaticResource} dans le dictionnaire « HighContrast ». Cette situation correspond à l’exception citée précédemment dans les recommandations. La plupart des valeurs de pinceau utilisées pour le thème « HighContrast » utilisent des choix de couleur qui sont contrôlés globalement par le système, mais exposés au code XAML sous forme d’une ressource spécialement nommée (ceux dont le nom comporte le préfixe SystemColor). Le système permet à l’utilisateur de définir les couleurs spécifiques qui doivent être utilisées pour leurs paramètres de thème à contraste via les Options d’ergonomie. Ces choix de couleur sont appliqués aux ressources spécialement nommées. L’infrastructure XAML utilise le même événement de modification de thème pour mettre également à jour ces pinceaux lorsqu’elle détecte une modification au niveau du système. C’est pourquoi l’extension de balisage {ThemeResource} est utilisée ici.