Risorse del tema XAML

Le risorse del tema in XAML sono un insieme di risorse che applicano valori diversi a seconda del tema di sistema attivo. Ci sono 3 temi che il framework XAML supporta: "Chiaro", "Scuro" e "Alto contrasto".

Prerequisiti: Questo argomento presuppone che tu abbia letto Dizionario delle risorse e riferimenti alle risorse XAML.

Risorse tematiche e risorse statiche

Esistono due estensioni di markup XAML che possono fare riferimento a una risorsa XAML da un dizionario di risorse XAML esistente: {StaticResource} estensione del markup e {ThemeResource} estensione del markup.

La valutazione di un'estensione di markup {ThemeResource} avviene al caricamento dell'applicazione e successivamente ogni volta che il tema viene modificato in fase di esecuzione. In genere ciò è dovuto alla modifica delle impostazioni del dispositivo da parte dell'utente o a una modifica programmatica all'interno dell'app che altera il tema corrente.

Al contrario, un'estensione di markup {StaticResource} viene valutata solo quando l'XAML viene caricato per la prima volta dall'applicazione. Non si aggiorna. È simile a un trova e sostituisci nel tuo XAML con il valore effettivo del runtime all'avvio dell'applicazione.

Risorse dei temi nella struttura del dizionario risorse

Ogni risorsa del tema fa parte del file XAML themeresources.xaml. Ai fini della progettazione, il file themeresources.xaml è disponibile nella cartella \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<Versione SDK>\Generic di un'installazione del Software Development Kit (SDK) di Windows. I dizionari delle risorse in themeresources.xaml sono riprodotti anche in generic.xaml nella stessa directory.

Windows Runtime non usa questi file fisici per la ricerca in fase di esecuzione. Ecco perché si trovano specificamente in una cartella DesignTime e non vengono copiati nelle applicazioni per impostazione predefinita. Invece, questi dizionari di risorse esistono in memoria come parte del Windows Runtime stesso e i riferimenti alle risorse XAML della tua applicazione alle risorse del tema (o alle risorse di sistema) si risolvono lì in fase di esecuzione.

Linee guida per le risorse del tema personalizzate

Puoi seguire queste linee guida per la definizione e l'uso di risorse del tema personalizzate:

  • Specifica i dizionari dei temi "Chiaro" e "Scuro" oltre al dizionario "Alto contrasto". Sebbene sia possibile creare un ResourceDictionary con "Default" come chiave, è preferibile essere espliciti e utilizzare "Light", "Dark" e "HighContrast".

  • Utilizza l'estensione di markup {ThemeResource} in: Stili, setter, modelli di controllo, setter di proprietà e animazioni.

  • Non usare l'estensione di markup {ThemeResource} nelle definizioni delle risorse all'interno di ThemeDictionaries. Usa invece l'estensione di markup {StaticResource} .

    ECCEZIONE: Puoi utilizzare l'estensione di markup {ThemeResource} per fare riferimento a risorse che non dipendono dal tema dell'applicazione nei tuoi ThemeDictionaries. Esempi di queste risorse sono i colori d'accento, come SystemAccentColor, o i colori di sistema, che di solito hanno il prefisso "SystemColor", come SystemColorButtonFaceColor.

Attenzione

Se non segui queste linee guida, potresti vedere un comportamento inaspettato legato ai temi nella tua applicazione. Per maggiori informazioni, consulta la sezione Risoluzione dei problemi del tema .

La rampa di colori XAML e i pennelli dipendenti dal tema

L'insieme dei colori per i temi "Light", "Dark" e "HighContrast" costituisce la rampa di colori di Windows in XAML. Se vuoi modificare i temi di sistema o applicare un tema ai tuoi elementi XAML, è importante capire come sono strutturate le risorse di colore.

Per altre informazioni su come applicare il colore nella tua app di Windows, vedi Colore nelle app di Windows.

Colori del tema chiaro e scuro

Il framework XAML fornisce una serie di risorse Color con valori personalizzati per i temi "Light" e "Dark". Per WinUI 2, le risorse del tema sono definite nel file Xaml Common theme resources. I nomi dei colori sono molto descrittivi dell'uso che se ne intende fare e c'è una risorsa SolidColorBrush corrispondente per ogni risorsa Color.

Suggerimento

Per una panoramica visiva di questi colori, consulta l'applicazione WinUI 3 Gallery: Colori

L'app Raccolta WinUI 3 include esempi interattivi della maggior parte dei controlli e delle funzionalità di WinUI 3. Scaricare l'app da Microsoft Store od ottenere il codice sorgente su GitHub

Colori del tema di contrasto del sistema Windows

Oltre all'insieme di risorse fornite dal framework XAML, c'è un insieme di valori di colore derivati dalla tavolozza di sistema di Windows. Questi colori non sono specifici delle app di Windows Runtime o di Windows. Tuttavia, molte delle risorse XAML Brush consumano questi colori quando il sistema è in funzione (e l'applicazione è in esecuzione) utilizzando il tema "HighContrast". Il framework XAML fornisce questi colori a livello di sistema come risorse con chiave. I tasti seguono il formato di denominazione: SystemColor[name]Color.

Per maggiori informazioni sul supporto dei temi di contrasto, consulta Temi di contrasto.

Colore d'accento del sistema

Oltre ai colori del tema di contrasto del sistema, il colore d'accento del sistema viene fornito come risorsa di colore speciale utilizzando il tasto SystemAccentColor. In fase di esecuzione, questa risorsa ottiene il colore che l'utente ha specificato come colore d'accento nelle impostazioni di personalizzazione di Windows.

Nota

Anche se è possibile sovrascrivere le risorse di colore del sistema, è buona norma rispettare le scelte cromatiche dell'utente, soprattutto per quanto riguarda le impostazioni dei temi di contrasto.

Spazzole dipendenti dal tema

Le risorse colore mostrate nelle sezioni precedenti sono utilizzate per impostare la proprietà Color delle risorse SolidColorBrush nei dizionari delle risorse del tema di sistema. Utilizza le risorse del pennello per applicare il colore agli elementi XAML.

Vediamo come il valore del colore di questo pennello viene determinato in fase di esecuzione. Nei dizionari delle risorse "Light" e "Dark", questo pennello è definito come segue:

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

Nel dizionario delle risorse "HighContrast", questo pennello è definito in questo modo:

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

Quando questo pennello viene applicato a un elemento XAML, il suo colore viene determinato in fase di esecuzione dal tema corrente, come mostrato in questa tabella.

Tema Risorse colore Valore di runtime
Chiaro TextFillColorPrimary #E4000000
Scuro TextFillColorPrimary #FFFFFFFF
HighContrast SystemColorWindowTextColor Il colore specificato nelle impostazioni per il Testo.

La rampa di tipo XAML

Il file themeresources.xaml definisce diverse risorse che definiscono uno stile che puoi applicare ai contenitori di testo nella tua interfaccia utente, in particolare per TextBlock o RichTextBlock. Questi non sono gli stili impliciti predefiniti. Vengono forniti per facilitare la creazione di definizioni XAML UI che corrispondono alla rampa di tipo Windows documentata in Guidelines for fonts.

Questi stili sono per gli attributi di testo che vuoi applicare all'intero contenitore di testo. Se vuoi che gli stili vengano applicati solo a sezioni di testo, imposta gli attributi sugli elementi di testo all'interno del contenitore, come ad esempio su un Run in TextBlock.Inlines o su un Paragraph in RichTextBlock.Blocks.

Gli stili appaiono così quando vengono applicati a un TextBlock :

text block styles

Style Peso Dimensione
Caption Regolare 12
Corpo Regolare 14
Corpo forte Semibold 14
Corpo Grande Regolare 18
Sottotitolo Semibold 20
Title Semibold 28
Titolo Grande Semibold 40
Schermo 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}"/>

Per indicazioni su come usare la gamma di dimensioni e formati previsti per Windows nella tua app, vedi Tipografia nelle app di Windows.

Per i dettagli sugli stili XAML, consulta WinUI su GitHub:

Suggerimento

Per una panoramica visiva di questi stili, consulta l'applicazione WinUI 3 Gallery: Tipografia

BaseRichTextBlockStyle

TargetType: RichTextBlock

Fornisce le proprietà comuni a tutti gli altri stili di contenitore di 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>

Nota: Gli stili di RichTextBlock non hanno tutti gli stili di rampa di testo di TextBlock , soprattutto perché il modello di oggetto del documento a blocchi di RichTextBlock rende più facile impostare gli attributi sui singoli elementi di testo. Inoltre, impostare TextBlock.Text utilizzando la proprietà XAML content introduce una situazione in cui non c'è alcun elemento di testo da stilizzare e quindi devi stilizzare il contenitore. Questo non rappresenta un problema per RichTextBlock, in quanto il relativo contenuto di testo deve sempre trovarsi in elementi di testo specifici come Paragraph, che è la posizione in cui potresti applicare degli stili XAML all'intestazione di pagina, al sottotitolo e a definizioni simili della gamma di dimensioni e formati previsti per il testo.

Vari stili denominati

C'è un'ulteriore serie di definizioni di Style chiave che puoi applicare per stilizzare un Button in modo diverso dal suo stile implicito predefinito.

TargetType: Pulsante

Questo Stile fornisce un modello completo per un Pulsante che può essere il pulsante di navigazione indietro di un'applicazione di navigazione. Le dimensioni predefinite sono 40 x 40 pixel. Per personalizzare lo stile, puoi impostare esplicitamente Height, Width, FontSize e altre proprietà per Button o creare uno stile derivato usando BasedOn.

Ecco un controllo Button con la risorsa NavigationBackButtonNormalStyle applicata.

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

Avrà l'aspetto seguente:

A button styled as a back button

TargetType: Pulsante

Questo Stile fornisce un modello completo per un Pulsante che può essere il pulsante di navigazione indietro di un'applicazione di navigazione. È simile a NavigationBackButtonNormalStyle, ma le dimensioni sono 30 x 30 pixel.

Ecco un controllo Button con la risorsa NavigationBackButtonSmallStyle applicata.

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

Risoluzione dei problemi delle risorse a tema

Se non segui le linee guida di per l'utilizzo delle risorse dei temi, potresti vedere un comportamento inaspettato legato ai temi nella tua applicazione.

Ad esempio, quando apri un flyout a tema chiaro, anche alcune parti della tua app a tema scuro cambiano come se fossero nel tema chiaro. Oppure se navighi verso una pagina a tema chiaro e poi torni indietro, la pagina originale a tema scuro (o parti di essa) appare come se fosse nel tema chiaro.

In genere, questo tipo di problemi si verifica quando si fornisce un tema "Default" e un tema "HighContrast" per supportare gli scenari ad alto contrasto e poi si utilizzano i temi "Light" e "Dark" in diverse parti dell'applicazione.

Ad esempio, considera questa definizione del dizionario dei temi:

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

Intuitivamente, questo sembra corretto. Vuoi cambiare il colore indicato da myBrush quando è ad alto contrasto, ma quando non è ad alto contrasto, ti affidi all'estensione di markup {ThemeResource} per assicurarti che myBrush punti al colore giusto per il tuo tema. Se la tua applicazione non ha mai impostato FrameworkElement.RequestedTheme sugli elementi della sua struttura visiva, di solito funziona come previsto. Tuttavia, si verificano dei problemi nella tua applicazione non appena inizi a ri-tematizzare diverse parti del tuo albero visivo.

Il problema si verifica perché i pennelli sono risorse condivise, a differenza della maggior parte degli altri tipi di XAML. Se hai due elementi in sottoalberi XAML con temi diversi che fanno riferimento alla stessa risorsa pennello, quando il framework passa ogni sottoalbero per aggiornare le sue espressioni {ThemeResource}, le modifiche alla risorsa pennello condivisa si riflettono nell'altro sottoalbero, il che non è il risultato desiderato.

Per risolvere questo problema, sostituisci il dizionario "Default" con dizionari separati per i temi "Light" e "Dark" oltre a "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>

Tuttavia, si verificano ancora dei problemi se una qualsiasi di queste risorse viene referenziata in proprietà ereditate come Foreground. Il tuo modello di controllo personalizzato potrebbe specificare il colore di primo piano di un elemento utilizzando l'estensione di markup {ThemeResource}, ma quando il framework propaga il valore ereditato agli elementi figli, fornisce un riferimento diretto alla risorsa risolta dall'espressione dell'estensione di markup {ThemeResource}. Ciò causa problemi quando il framework elabora le modifiche al tema mentre percorre l'albero visivo del tuo controllo. Rivaluta l'espressione di estensione del markup {ThemeResource} per ottenere una nuova risorsa pennello, ma non propaga ancora questo riferimento ai figli del controllo; questo avviene in un secondo momento, ad esempio durante il prossimo passaggio di misura.

Di conseguenza, dopo aver percorso l'albero visivo dei controlli in risposta a una modifica del tema, il framework percorre i figli e aggiorna le espressioni {ThemeResource} dell'estensione impostate su di essi o sugli oggetti impostati sulle loro proprietà. È qui che si verifica il problema: il framework passa alla risorsa pennello e, poiché specifica il suo colore utilizzando un'estensione di markup {ThemeResource}, viene rivalutato.

A questo punto, il framework sembra aver inquinato il dizionario del tuo tema perché ora ha una risorsa di un dizionario che ha il suo colore impostato da un altro dizionario.

Per risolvere questo problema, usa l'estensione di markup {StaticResource} invece di {ThemeResource}. Con le linee guida applicate, i dizionari tematici si presentano così:

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

Nota che l'estensione di markup {ThemeResource} è ancora utilizzata nel dizionario "HighContrast" invece dell'estensione di markup {StaticResource}. Questa situazione rientra nell'eccezione indicata in precedenza nelle linee guida. La maggior parte dei valori dei pennelli utilizzati per il tema "HighContrast" utilizza scelte di colore controllate globalmente dal sistema, ma esposte a XAML come risorse con nomi speciali (quelli preceduti da 'SystemColor' nel nome). Il sistema consente all'utente di impostare i colori specifici da utilizzare per le impostazioni del tema di contrasto attraverso il Centro di accesso facilitato. Queste scelte cromatiche vengono applicate alle risorse con un nome specifico. Il framework XAML utilizza lo stesso evento di modifica del tema per aggiornare anche questi pennelli quando rileva che sono stati modificati a livello di sistema. Per questo motivo viene utilizzata l'estensione di markup {ThemeResource}.