XAML-Themenressourcen

Designressourcen in XAML sind Ressourcen, die abhängig vom aktiven Systemdesign verschiedene Werte anwenden. Es gibt drei Designs, die vom XAML-Framework unterstützt werden: "Light", "Dark" und "HighContrast".

Voraussetzungen: In diesem Thema wird davon ausgegangen, dass Sie ResourceDictionary- und XAML-Ressourcenverweise gelesen haben.

Themenressourcen v. statische Ressourcen

Es gibt zwei XAML-Markuperweiterungen, die aus einem vorhandenen XAML-Ressourcenwörterbuch auf eine XAML-Ressource verweisen können: {StaticResource}-Markuperweiterung und {ThemeResource}-Markuperweiterung.

Die Auswertung einer {ThemeResource}-Markuperweiterung erfolgt, wenn die App geladen wird und anschließend jedes Mal, wenn sich das Design zur Laufzeit ändert. Dies ist in der Regel das Ergebnis, dass der Benutzer seine Geräteeinstellungen oder eine programmgesteuerte Änderung innerhalb der App ändert, die das aktuelle Design ändert.

Im Gegensatz dazu wird eine {StaticResource}-Markuperweiterung nur ausgewertet, wenn der XAML-Code zuerst von der App geladen wird. Es wird nicht aktualisiert. Dies ähnelt dem Suchen und Ersetzen in XAML-Code mit dem tatsächlichen Laufzeitwert beim Start der App.

Themenressourcen in der Ressourcenwörterbuchstruktur

Jede Themenressource ist Teil der XAML-Datei "themeresources.xaml". Für Entwurfszwecke ist die Datei themeresources.xaml im Ordner \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic innerhalb einer Windows Software Development Kit (SDK)-Installation verfügbar. Die Ressourcenverzeichnisse in „themeresources.xaml“ werden auch in „generic.xaml“ im selben Verzeichnis reproduziert.

Die Windows-Runtime verwendet diese physischen Dateien nicht für die Laufzeitsuche. Deshalb befinden sie sich speziell in einem DesignTime-Ordner und werden nicht standardmäßig in Apps kopiert. Stattdessen sind die Ressourcenverzeichnisse als Teil der Windows-Runtime selbst im Speicher vorhanden, und die XAML-Ressource Ihrer App verweist auf Designressourcen (oder Systemressourcen), die dort zu Laufzeit aufgelöst werden.

Richtlinien für benutzerdefinierte Designressourcen

Befolgen Sie diese Richtlinien, wenn Sie Ihre eigenen benutzerdefinierten Designressourcen definieren und nutzen:

Vorsicht

Wenn Sie diesen Richtlinien nicht folgen, kann ein unerwartetes Verhalten im Zusammenhang mit Designs in Ihrer App auftreten. Weitere Informationen finden Sie im Abschnitt "Ressourcen zur Fehlerbehebung im Thema".

Die XAML-Farbskala und designabhängige Pinsel

Die kombinierten Farben für die Designs "Light", "Dark" und "HighContrast" bilden den Windows-Farbverlauf in XAML. Ganz gleich, ob Sie die Systemdesigns ändern oder ein Design auf Ihre eigenen XAML-Elemente anwenden möchten, es ist wichtig zu verstehen, wie die Farbressourcen strukturiert sind.

Weitere Informationen zum Anwenden von Farben in Ihrem Windows app finden Sie unter Color in Windows-Apps.

Helle und dunkle Themenfarben

Das XAML-Framework stellt einen Satz benannter Farbressourcen mit Werten bereit, die auf die Designs "Light" und "Dark" zugeschnitten sind. Für WinUI werden die Designressourcen in der Xaml-Datei "Common theme resources" definiert. Die Farbnamen sind sehr beschreibend und weisen auf die beabsichtigte Verwendung hin. Es gibt jeweils eine SolidColorBrush-Ressource für jede Color-Ressource.

Tipp

Eine visuelle Übersicht über diese Farben finden Sie in der WinUI 3 Gallery-App: Farben

Die WinUI 3 Gallery-App enthält interaktive Beispiele für die meisten WinUI-Steuerelemente, Features und Funktionen. Rufen Sie die App aus dem Microsoft Store ab, oder rufen Sie den Quellcode auf GitHub

Kontrastfarbthemen für Windows-Systeme

Zusätzlich zu den Ressourcen, die vom XAML-Framework bereitgestellt werden, gibt es eine Reihe von Farbwerten, die von der Windows-Systempalette abgeleitet werden. Diese Farben sind für die Windows-Runtime- oder Windows-Apps nicht spezifisch. Viele der XAML-Pinselressourcen verwenden diese Farben, wenn das System mit dem "HighContrast"-Theme betrieben wird und die App läuft. Das XAML-Framework stellt diese systemweiten Farben als Schlüsselressourcen bereit. Die Schlüssel folgen dem Benennungsformat: SystemColor[name]Color.

Weitere Informationen zur Unterstützung von Kontrastdesigns finden Sie unter Kontrastdesigns.

Systemakzentfarbe

Neben der Systemdesignfarben mit hohem Kontrast wird die Akzentfarbe des Systems als spezielle Ressource mit dem Schlüssel SystemAccentColor bereitgestellt. Zur Laufzeit ruft diese Ressource die Farbe ab, die der Benutzer in den Windows-Personalisierungseinstellungen als Akzentfarbe angegeben hat.

Hinweis

Obwohl es möglich ist, die Systemfarbressourcen außer Kraft zu setzen, empfiehlt es sich, die Farbauswahl des Benutzers zu berücksichtigen, insbesondere für Kontrastdesigneinstellungen.

Themenabhängige Pinsel

Die in den vorherigen Abschnitten gezeigten Farbressourcen dienen zum Festlegen der Color-Eigenschaft von SolidColorBrush-Ressourcen in den Systemdesign-Ressourcenwörterbüchern. Sie verwenden die Pinselressourcen, um die Farbe auf XAML-Elemente anzuwenden.

Sehen wir uns an, wie der Farbwert für diesen Pinsel zur Laufzeit bestimmt wird. In den Ressourcenverzeichnissen „Light“ und „Dark“ wird dieser Pinsel wie folgt definiert:

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

Im Ressourcenverzeichnis "HighContrast" wird dieser Pinsel wie folgt definiert:

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

Wenn dieser Pinsel auf ein XAML-Element angewendet wird, wird die Farbe zur Laufzeit durch das aktuelle Design bestimmt, wie in dieser Tabelle dargestellt.

Thema Farbressource Laufzeitwert
Licht TextFillColorPrimary #E4000000
Dunkel TextFillColorPrimary #FFFFFFFF
HighContrast SystemColorWindowTextColor Die in den Einstellungen für Text angegebene Farbe.

Die XAML-Typskala

Die Datei themeresources.xaml definiert mehrere Ressourcen, die eine Formatvorlage definieren, die Sie auf Textcontainer in Ihrer Benutzeroberfläche anwenden können, insbesondere für TextBlock oder RichTextBlock. Dies sind nicht die impliziten Standardstile. Sie werden bereitgestellt, um Ihnen das Erstellen von XAML-UI-Definitionen zu erleichtern, die der Windows-Typhierarchie entsprechen, die in Richtlinien für Schriftarten dokumentiert ist.

Diese Formatvorlagen gelten für Textattribute, die Auf den gesamten Textcontainer angewendet werden sollen. Wenn Formatvorlagen nur auf Abschnitte des Texts angewendet werden sollen, legen Sie Attribute für die Textelemente im Container fest, z. B. auf einer Run in TextBlock.Inlines oder auf einem Paragraf in RichTextBlock.Blocks.

Die Formatvorlagen sehen wie folgt aus, wenn sie auf einen TextBlock angewendet werden:

Textblockformatvorlagen

Stil Weight Size
Überschrift Regelmäßig 12
Body Regelmäßig 14
Körper stark Halbfett 14
Body Large Regelmäßig 18
Body Large Strong Halbfett 18
Untertitel Halbfett 20
Title Halbfett 28
Titel Großformat Halbfett 40
Display Halbfett 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="Body Large Strong" Style="{StaticResource BodyLargeStrongTextBlockStyle}"/>
<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}"/>

Eine Anleitung zur Verwendung der Windows-Typhierarchie in Ihrer App finden Sie unter Typografie in Windows-Apps.

Ausführliche Informationen zu den XAML-Stilen finden Sie unter WinUI auf GitHub:

Tipp

Eine visuelle Übersicht über diese Stile finden Sie in der WinUI 3 Gallery-App: Typografie

BaseRichTextBlockStyle

TargetType: RichTextBlock

Stellt die allgemeinen Eigenschaften für alle anderen RichTextBlock-Containerstile bereit.

<!-- Usage -->
<RichTextBlock Style="{StaticResource BaseRichTextBlockStyle}">
    <Paragraph>Rich text.</Paragraph>
</RichTextBlock>

<!-- Style definition -->
<Style x:Key="BaseRichTextBlockStyle" TargetType="RichTextBlock">
    <Setter Property="FontFamily" Value="Segoe UI Variable"/>
    <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>

Hinweis: Die RichTextBlock-Stile verfügen nicht über alle Textskala-Stile von TextBlock. Dies liegt hauptsächlich daran, dass das blockbasierte Dokumentobjektmodell für RichTextBlock das Festlegen von Attributen für die einzelnen Textelemente vereinfacht. Außerdem führt das Festlegen von "TextBlock.Text " mithilfe der XAML-Inhaltseigenschaft zu einer Situation, in der kein Textelement zum Formatieren vorhanden ist und Sie daher den Container formatieren müssen. Das ist kein Problem für RichTextBlock , da sich der Textinhalt immer in bestimmten Textelementen wie Paragraph befinden muss. Hier können Sie XAML-Formatvorlagen für Seitenüberschriften, Seitenunterüberschriften und ähnliche Texthierarchiedefinitionen anwenden.

Verschiedene benannte Formatvorlagen

Es gibt einen zusätzlichen Satz von Stildefinitionen mit Schlüsseln, die Sie anwenden können, um eine Schaltfläche anders als die implizite Standardformatvorlage zu formatieren.

TargetType: Button

Diese Formatvorlage bietet eine vollständige Vorlage für eine Schaltfläche , die die Navigationsschaltfläche "Zurück" für eine Navigations-App sein kann. Die Standardabmessungen sind 40 x 40 Pixel. Um die Formatierung anzupassen, können Sie entweder explizit die Eigenschaften "Height", "Width", "FontSize" und andere Eigenschaften auf der Schaltfläche festlegen oder eine abgeleitete Formatvorlage mithilfe von BasedOn erstellen.

Hier ist eine Schaltfläche, der die Ressource NavigationBackButtonNormalStyle zugewiesen wurde.

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

Dies sieht wie folgt aus:

Eine Schaltfläche, die als Schaltfläche

TargetType: Button

Diese Formatvorlage bietet eine vollständige Vorlage für eine Schaltfläche , die die Navigationsschaltfläche "Zurück" für eine Navigations-App sein kann. Es ist ähnlich wie NavigationBackButtonNormalStyle, aber seine Abmessungen sind 30 x 30 Pixel.

Hier ist eine Schaltfläche , auf die die NavigationBackButtonSmallStyle-Ressource angewendet wurde.

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

Problembehandlung bei Themenressourcen

Wenn Sie die Richtlinien für die Verwendung von Designressourcen nicht befolgen, wird möglicherweise unerwartetes Verhalten im Zusammenhang mit Designs in Ihrer App angezeigt.

Wenn Sie z. B. ein Flyout mit hellem Thema öffnen, ändern sich Teile Ihrer App mit dunklem Thema auch so, als wären sie im hellen Thema. Oder wenn Sie zu einer hellen Designseite navigieren und dann zurück navigieren, sieht die ursprüngliche seite mit dunklem Design (oder Teile davon) nun so aus, als ob sie sich im hellen Design befindet.

In der Regel treten diese Arten von Problemen auf, wenn Sie ein "Standard"-Design und ein "HighContrast"-Design für Szenarien mit hohem Kontrast anbieten, und dann sowohl die Designs "Hell" als auch "Dunkel" in verschiedenen Teilen Ihrer App verwenden.

Betrachten Sie beispielsweise diese Definition im Themenwörterbuch:

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

Intuitiv sieht dies richtig aus. Sie möchten die Farbe ändern, auf die myBrush bei Verwendung von hohem Kontrast verweist, aber wenn kein hoher Kontrast verwendet wird, nutzen Sie die {ThemeResource}-Markuperweiterung, um sicherzustellen, dass myBrush auf die richtige Farbe für Ihr Design verweist. Wenn Ihre App niemals FrameworkElement.RequestedTheme auf Elemente innerhalb ihres visuellen Baums festlegt, funktioniert dies in der Regel wie erwartet. In Ihrer App treten jedoch Probleme auf, sobald Sie beginnen, verschiedene Teile Ihres visuellen Baums umzugestalten.

Das Problem tritt auf, da Pinsel gemeinsame Ressourcen sind, anders als die meisten anderen XAML-Typen. Wenn Sie zwei Elemente in XAML-Unterstrukturen mit unterschiedlichen Designs haben, die auf dieselbe Pinselressource verweisen, wird bei der Durchforstung jeder Unterstruktur durch das Framework, um die {ThemeResource}-Markuperweiterungsausdrücke zu aktualisieren, eine Änderung an der geteilten Pinselressource auch in der anderen Unterstruktur widergespiegelt. Dies entspricht nicht Ihrem beabsichtigten Ergebnis.

Um dies zu beheben, ersetzen Sie das Wörterbuch "Standard" durch separate Themenwörterbücher für die Themen "Light" und "Dark" zusätzlich zu "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>

Es treten jedoch weiterhin Probleme auf, wenn auf eine dieser Ressourcen in geerbten Eigenschaften wie "Foreground" verwiesen wird. Ihre benutzerdefinierte Steuerelementvorlage kann die Vordergrundfarbe eines Elements mithilfe der {ThemeResource}-Markuperweiterung angeben, aber wenn das Framework den geerbten Wert an untergeordnete Elemente weitergibt, stellt sie einen direkten Verweis auf die Ressource bereit, die vom {ThemeResource}-Markuperweiterungsausdruck aufgelöst wurde. Dies führt zu Problemen, wenn das Framework Designänderungen verarbeitet, während es die visuelle Struktur des Steuerelements durchläuft. Es wertet den Ausdruck der {ThemeResource}-Markuperweiterung neu aus, um eine neue Pinselressource abzurufen, gibt diesen Verweis aber noch nicht an die untergeordneten Elemente des Steuerelements weiter. Dies geschieht später, zum Beispiel beim nächsten Messwertdurchlauf.

Nach dem Durchlaufen der visuellen Struktur des Steuerelements in Reaktion auf eine Designänderung durchläuft das Framework daher die untergeordneten Elemente und aktualisiert Ausdrücke der {ThemeResource}-Markuperweiterung für sie oder für Objekte, die für ihre Eigenschaften festgelegt sind. Hier tritt das Problem auf. Das Framework durchläuft die Pinselressource, und da die Farbe mit einer {ThemeResource}-Markuperweiterung angegeben wird, erfolgt eine erneute Auswertung.

An dieser Stelle hat das Framework Ihr Designverzeichnis anscheinend „verunreinigt“, da es jetzt eine Ressource aus einem Verzeichnis enthält, für die die Farbe durch ein anderes Verzeichnis festgelegt wird.

Um dieses Problem zu beheben, verwenden Sie die {StaticResource}-Markuperweiterung anstelle der {ThemeResource}-Markuperweiterung. Mit den angewendeten Richtlinien sehen die Themenwörterbücher wie folgt aus:

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

Beachten Sie, dass die {ThemeResource}-Markuperweiterung weiterhin im Wörterbuch "HighContrast" anstelle der {StaticResource}-Markuperweiterung verwendet wird. Diese Situation fällt unter die zuvor in den Richtlinien angeführte Ausnahme. Die meisten Pinselwerte für das HighContrast-Design verwenden eine Farbauswahl, die global vom System gesteuert wird, aber für XAML als Ressource mit einem speziellen Namen (mit dem Präfix „SystemColor“) verfügbar gemacht wird. Das System ermöglicht es dem Benutzer, die spezifischen Farben festzulegen, die für seine Kontrastdesign-Einstellungen über das Zentrum für erleichterten Zugriff verwendet werden sollen. Diese Farbauswahl wird auf die speziell benannten Ressourcen angewendet. Das XAML-Framework verwendet dieses Thema-Änderungsereignis, um diese Brushes auch zu aktualisieren, wenn erkannt wird, dass sie auf Systemebene geändert wurden. Aus diesem Grund wird hier die {ThemeResource}-Markuperweiterung verwendet.