Compartilhar via


Recursos de temas XAML

Os recursos de tema no XAML são um conjunto de recursos que aplicam valores diferentes dependendo de qual tema do sistema está ativo. Há três temas que a estrutura XAML dá suporte: "Claro", "Escuro" e "HighContrast".

Pré-requisitos: este tópico pressupõe que você tenha lido referências de recurso ResourceDictionary e XAML.

Recursos de tema v. recursos estáticos

Há duas extensões de marcação XAML que podem referenciar um recurso XAML de um dicionário de recursos XAML existente: extensão de marcação {StaticResource} e extensão de marcação {ThemeResource}.

A avaliação de uma extensão de marcação {ThemeResource} ocorre quando o aplicativo é carregado e, posteriormente, cada vez que o tema é alterado em runtime. Normalmente, isso é o resultado da alteração das configurações do dispositivo ou de uma alteração programática dentro do aplicativo que altera seu tema atual.

Por outro lado, uma extensão de marcação {StaticResource} é avaliada somente quando o XAML é carregado pela primeira vez pelo aplicativo. Ele não é atualizado. É semelhante a uma localização e substituição em seu XAML pelo valor real do runtime na inicialização do aplicativo.

Recursos de tema na estrutura do dicionário de recursos

Cada recurso de tema faz parte do arquivo XAML themeresources.xaml. Para fins de design, themeresources.xaml está disponível na pasta \(Arquivos de Programas)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic de uma instalação do SDK (Windows Software Development Kit). Os dicionários de recursos em themeresources.xaml também são reproduzidos em generic.xaml no mesmo diretório.

O Windows Runtime não usa esses arquivos físicos para pesquisa de runtime. É por isso que eles estão especificamente em uma pasta DesignTime e não são copiados para aplicativos por padrão. Em vez disso, esses dicionários de recursos existem na memória como parte do próprio Windows Runtime e as referências de recurso XAML do seu aplicativo a recursos de tema (ou recursos do sistema) são resolvidas lá em runtime.

Diretrizes para recursos de tema personalizados

Siga estas diretrizes ao definir e consumir seus próprios recursos de tema personalizados:

Cuidado

Se você não seguir essas diretrizes, poderá ver um comportamento inesperado relacionado a temas em seu aplicativo. Para obter mais informações, consulte a seção De recursos de tema de solução de problemas .

A rampa de cores XAML e pincéis dependentes de tema

O conjunto combinado de cores para temas "Claro", "Escuro" e "HighContrast" compõem a rampa de cores do Windows em XAML. Se você deseja modificar os temas do sistema ou aplicar um tema aos seus próprios elementos XAML, é importante entender como os recursos de cor são estruturados.

Para obter informações adicionais sobre como aplicar cor em seu aplicativo do Windows, consulte Cor nos aplicativos do Windows.

Cores de tema claro e escuro

A estrutura XAML fornece um conjunto de recursos de cores nomeados com valores personalizados para os temas "Claro" e "Escuro". Para o WinUI 2, os recursos de tema são definidos no arquivo Xaml de recursos de tema comuns. Os nomes de cores são muito descritivos do uso pretendido e há um recurso SolidColorBrush correspondente para cada recurso color.

Dica

Para obter uma visão geral visual dessas cores, consulte o aplicativo Da Galeria do WinUI 3: Cores

O aplicativo da Galeria do WinUI 3 inclui exemplos interativos da maioria dos controles, recursos e funcionalidades do WinUI 3. Obtenha o aplicativo na Microsoft Store ou obtenha o código-fonte no GitHub

Cores do tema de contraste do sistema Windows

Além do conjunto de recursos fornecido pela estrutura XAML, há um conjunto de valores de cores derivados da paleta do sistema Windows. Essas cores não são específicas para os aplicativos windows runtime ou Windows. No entanto, muitos dos recursos do Pincel XAML consomem essas cores quando o sistema está operando (e o aplicativo está em execução) usando o tema "HighContrast". A estrutura XAML fornece essas cores em todo o sistema como recursos chaveados. As chaves seguem o formato de nomenclatura: SystemColor[name]Color.

Para obter mais informações sobre como dar suporte a temas de contraste, consulte Temas de contraste.

Cor de ênfase do sistema

Além das cores do tema de contraste do sistema, a cor de destaque do sistema é fornecida como um recurso de cor especial usando a chave SystemAccentColor. Em runtime, esse recurso obtém a cor especificada pelo usuário como a cor de destaque nas configurações de personalização do Windows.

Observação

Embora seja possível substituir os recursos de cor do sistema, é uma prática recomendada respeitar as opções de cores do usuário, especialmente para as configurações de tema de contraste.

Pincéis dependentes de tema

Os recursos de cor mostrados nas seções anteriores são usados para definir a propriedade Color dos recursos SolidColorBrush nos dicionários de recursos de tema do sistema. Use os recursos de pincel para aplicar a cor aos elementos XAML.

Vamos examinar como o valor de cor desse pincel é determinado em tempo de execução. Nos dicionários de recursos "Claro" e "Escuro", esse pincel é definido da seguinte maneira:

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

No dicionário de recursos "HighContrast", esse pincel é definido da seguinte maneira:

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

Quando esse pincel é aplicado a um elemento XAML, sua cor é determinada em tempo de execução pelo tema atual, conforme mostrado nesta tabela.

Tema Recurso de cor Valor do runtime
Leve TextFillColorPrimary #E4000000
Escuro TextFillColorPrimary #FFFFFFFF
HighContrast SystemColorWindowTextColor A cor especificada nas configurações de Texto.

A rampa de tipo XAML

O arquivo themeresources.xaml define vários recursos que definem um Estilo que você pode aplicar a contêineres de texto em sua interface do usuário, especificamente para TextBlock ou RichTextBlock. Esses não são os estilos implícitos padrão. Eles são fornecidos para facilitar a criação de definições de interface do usuário XAML que correspondam à rampa de tipo do Windows documentada em Diretrizes para fontes.

Esses estilos são para atributos de texto que você deseja aplicar ao contêiner de texto inteiro. Se você quiser estilos aplicados apenas a seções do texto, defina atributos nos elementos de texto dentro do contêiner, como em uma execução em TextBlock.Inlines ou em um parágrafo em RichTextBlock.Blocks.

Os estilos se parecem com este quando aplicados a um TextBlock:

estilos de bloco de texto

Estilo Weight Tamanho
Legenda Regular 12
Corpo Regular 14
Corpo Forte Semibold 14
Corpo Grande Regular 18
Subtítulo Semibold 20
Title Semibold 28
Título grande 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}"/>

Para obter diretrizes sobre como usar a rampa de tipo do Windows em seu aplicativo, consulte Tipografia em aplicativos do Windows.

Para obter detalhes sobre os estilos XAML, consulte WinUI no GitHub:

Dica

Para obter uma visão geral visual desses estilos, consulte o aplicativo Da Galeria do WinUI 3: Tipografia

BaseRichTextBlockStyle

TargetType: RichTextBlock

Fornece as propriedades comuns para todos os outros estilos de contêiner 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>

Observação: os estilos RichTextBlock não têm todos os estilos de rampa de texto que o TextBlock faz, principalmente porque o modelo de objeto de documento baseado em bloco para RichTextBlock facilita a definição de atributos nos elementos de texto individuais. Além disso, definir TextBlock.Text usando a propriedade de conteúdo XAML introduz uma situação em que não há nenhum elemento de texto para o estilo e, portanto, você teria que estilizar o contêiner. Isso não é um problema para RichTextBlock porque seu conteúdo de texto sempre precisa estar em elementos de texto específicos, como Parágrafo, que é onde você pode aplicar estilos XAML para cabeçalho de página, subtítulo de página e definições de rampa de texto semelhantes.

Estilos nomeados diversos

Há um conjunto adicional de definições de estilo com chave que você pode aplicar ao estilo de um botão de forma diferente do estilo implícito padrão.

TargetType: Botão

Este Estilo fornece um modelo completo para um Botão que pode ser o botão voltar de navegação para um aplicativo de navegação. As dimensões padrão são 40 x 40 pixels. Para adaptar o estilo, você pode definir explicitamente as propriedades Height, Width, FontSize e outras propriedades no botão ou criar um estilo derivado usando BasedOn.

Aqui está um botão com o recurso NavigationBackButtonNormalStyle aplicado a ele.

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

Tem esta aparência:

Um botão estilizado como um botão voltar

TargetType: Botão

Este Estilo fornece um modelo completo para um Botão que pode ser o botão voltar de navegação para um aplicativo de navegação. É semelhante a NavigationBackButtonNormalStyle, mas suas dimensões são de 30 x 30 pixels.

Aqui está um botão com o recurso NavigationBackButtonSmallStyle aplicado a ele.

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

Solução de problemas de recursos de tema

Se você não seguir as diretrizes para usar recursos de tema, poderá ver um comportamento inesperado relacionado a temas em seu aplicativo.

Por exemplo, quando você abre um submenu com tema claro, partes do seu aplicativo com tema escuro também mudam como se estivessem no tema claro. Ou se você navegar até uma página com tema claro e depois navegar para trás, a página original com tema escuro (ou partes dela) agora parece estar no tema claro.

Normalmente, esses tipos de problemas ocorrem quando você fornece um tema "Padrão" e um tema "HighContrast" para dar suporte a cenários de alto contraste e, em seguida, usa temas "Claro" e "Escuro" em diferentes partes do seu aplicativo.

Por exemplo, considere esta definição de dicionário de temas:

<!-- 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, isso parece correto. Você deseja alterar a cor apontada quando myBrush estiver em alto contraste, mas quando não estiver em alto contraste, você conta com a extensão de marcação {ThemeResource} para garantir que aponte myBrush para a cor certa para o tema. Se seu aplicativo nunca tiver FrameworkElement.RequestedTheme definido em elementos dentro de sua árvore visual, isso normalmente funcionará conforme o esperado. No entanto, você tem problemas em seu aplicativo assim que começa a remendar diferentes partes da árvore visual.

O problema ocorre porque pincéis são recursos compartilhados, ao contrário da maioria dos outros tipos de XAML. Se você tiver dois elementos em subárvores XAML com temas diferentes que fazem referência ao mesmo recurso de pincel, à medida que a estrutura orienta cada subárvore para atualizar suas expressões de extensão de marcação {ThemeResource} , as alterações no recurso de pincel compartilhado são refletidas na outra subárvore, que não é o resultado pretendido.

Para corrigir isso, substitua o dicionário "Padrão" por dicionários de temas separados para temas "Claro" e "Escuro", além de "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>

No entanto, problemas ainda ocorrerão se qualquer um desses recursos for referenciado em propriedades herdadas, como Foreground. Seu modelo de controle personalizado pode especificar a cor de primeiro plano de um elemento usando a extensão de marcação {ThemeResource}, mas quando a estrutura propaga o valor herdado para elementos filho, ele fornece uma referência direta ao recurso que foi resolvido pela expressão de extensão de marcação {ThemeResource}. Isso causa problemas quando a estrutura processa alterações de tema à medida que percorre a árvore visual do controle. Ele reavalia a expressão de extensão de marcação {ThemeResource} para obter um novo recurso de pincel, mas ainda não propaga essa referência para os filhos do seu controle; isso acontece mais tarde, como durante a próxima aprovação de medida.

Como resultado, depois de percorrer a árvore visual de controle em resposta a uma alteração de tema, a estrutura orienta os filhos e atualiza as expressões de extensão de marcação {ThemeResource} definidas nelas ou em objetos definidos em suas propriedades. É aqui que ocorre o problema; a estrutura orienta o recurso de pincel e, como especifica sua cor usando uma extensão de marcação {ThemeResource}, ela é reavaliada.

Neste ponto, a estrutura parece ter poluído seu dicionário de temas porque agora tem um recurso de um dicionário que tem seu conjunto de cores de outro dicionário.

Para corrigir esse problema, use a extensão de marcação {StaticResource} em vez da extensão de marcação {ThemeResource}. Com as diretrizes aplicadas, os dicionários de temas são semelhantes a este:

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

Observe que a extensão de marcação {ThemeResource} ainda é usada no dicionário "HighContrast" em vez da extensão de marcação {StaticResource}. Essa situação se enquadra na exceção fornecida anteriormente nas diretrizes. A maioria dos valores de pincel usados para o tema "HighContrast" está usando opções de cores que são globalmente controladas pelo sistema, mas expostas ao XAML como um recurso especialmente nomeado (aqueles prefixados com 'SystemColor' no nome). O sistema permite que o usuário defina as cores específicas que devem ser usadas para suas configurações de tema de contraste por meio da Central de Facilidade de Acesso. Essas opções de cor são aplicadas aos recursos especialmente nomeados. A estrutura XAML usa o mesmo evento de alteração de tema para também atualizar esses pincéis quando detecta que eles foram alterados no nível do sistema. É por isso que a extensão de marcação {ThemeResource} é usada aqui.