Referências de recursos de ResourceDictionary e XAML
Você pode definir a interface do usuário ou os recursos para seu aplicativo usando XAML. Recursos geralmente são definições de algum objeto que você espera usar mais de uma vez. Para fazer referência a um recurso XAML posteriormente, especifique uma chave para um recurso que funcione como seu nome. Você pode fazer referência a um recurso em um aplicativo ou em qualquer página XAML dentro dele. É possível definir seus recursos usando um elemento ResourceDictionary do XAML do Windows Runtime. Em seguida, você pode fazer referência aos seus recursos usando uma extensão de marcação StaticResource ou uma extensão de marcação ThemeResource.
Os elementos XAML que podem ser declarados com mais frequência como recursos XAML incluem Style, ControlTemplate, componentes de animação e subclasses Brush. Aqui, explicaremos como definir um elemento ResourceDictionary e os recursos inseridos, e também como os recursos XAML se relacionam com outros recursos definidos como parte do aplicativo ou do pacote do aplicativo. Também explicaremos as características avançadas do dicionário de recursos como MergedDictionaries e ThemeDictionaries.
Pré-requisitos
Uma compreensão sólida da marcação XAML. Recomendamos a leitura da Visão geral de XAML.
Definir e usar recursos XAML
Os recursos XAML são objetos referenciados a partir da marcação mais de uma vez. Os recursos são definidos em um ResourceDictionary, normalmente em um arquivo separado ou na parte superior da página de marcação, como esta.
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:String x:Key="greeting">Hello world</x:String>
<x:String x:Key="goodbye">Goodbye world</x:String>
</Page.Resources>
<TextBlock Text="{StaticResource greeting}" Foreground="Gray" VerticalAlignment="Center"/>
</Page>
Neste exemplo:
<Page.Resources>…</Page.Resources>
– Define o dicionário de recursos.<x:String>
– Define o recurso com a tecla “saudação”.{StaticResource greeting}
– pesquisa o recurso com a chave "greeting", que é atribuída à propriedade Text de TextBlock.
Observação Não confunda os conceitos relacionados a ResourceDictionary com a ação de compilação Resource, arquivos de recursos (.resw) ou outros "recursos" que são abordados no contexto de estruturação do projeto de código que produz seu pacote do aplicativo.
Os recursos não precisam ser cadeias de caracteres; eles podem ser qualquer objeto compartilhável, como estilos, modelos, pincéis e cores. Entretanto, controles, formas e outros FrameworkElements não são compartilháveis, então não podem ser declarados como recursos reutilizáveis. Para obter mais informações sobre compartilhamento, consulte a seção Recursos XAML devem ser compartilháveis mais adiante neste tópico.
Aqui, um pincel e uma cadeia de caracteres são declarados como recursos e usados por controles em uma página.
<Page
x:Class="SpiderMSDN.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<SolidColorBrush x:Key="myFavoriteColor" Color="green"/>
<x:String x:Key="greeting">Hello world</x:String>
</Page.Resources>
<TextBlock Foreground="{StaticResource myFavoriteColor}" Text="{StaticResource greeting}" VerticalAlignment="Top"/>
<Button Foreground="{StaticResource myFavoriteColor}" Content="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>
Todos os recursos precisam ter uma chave. Normalmente, essa chave é uma cadeia de caracteres definida com x:Key="myString"
. No entanto, há algumas outras maneiras de especificar uma chave:
- Style e ControlTemplate exigem um TargetType e usarão o TargetType como a chave se x:Key não for especificado. Nesse caso, a chave é o objeto Type real, não uma cadeia de caracteres. (Veja exemplos abaixo)
- Os recursos DataTemplate com um TargetType usarão o TargetType como a chave se x:Key não for especificado. Nesse caso, a chave é o objeto Type real, não uma cadeia de caracteres.
- x:Name pode ser usado em vez de x:Key. No entanto, x:Name também gera um campo code-behind para o recurso. Como resultado, x:Name é menos eficiente que x:Key porque esse campo precisa ser inicializado quando a página é carregada.
A extensão de marcação StaticResource pode recuperar recursos somente com um nome de cadeia de caracteres (x:Key ou x:Name). Porém, a estrutura XAML também procura recursos de estilo implícito (aqueles que usam TargetType em vez de x:Key ou x:Name) quando ela decide o estilo e o modelo a serem usados para um controle que não definiu as propriedades Style e ContentTemplate ou ItemTemplate.
Aqui, Style tem uma chave implícita typeof(Button) e, desde que Button na parte inferior da página não especifique uma propriedade Style, ele procura um estilo com a chave typeof(Button):
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Red"/>
</Style>
</Page.Resources>
<Grid>
<!-- This button will have a red background. -->
<Button Content="Button" Height="100" VerticalAlignment="Center" Width="100"/>
</Grid>
</Page>
Para obter mais informações sobre estilos implícitos e como eles funcionam, consulte Aplicando estilos a controles e Modelos de controle.
Procurar recursos no código
Você acessa membros do dicionário de recursos como qualquer outro dicionário.
Aviso
Quando você executa uma pesquisa de recursos no código, somente os recursos no dicionário Page.Resources
são examinados. Ao contrário da extensão de marcação StaticResource, o código não retorna ao dicionário Application.Resources
se os recursos não forem encontrados no primeiro dicionário.
Este exemplo mostra como recuperar o recurso redButtonStyle
do dicionário de recursos de uma página:
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="Button" x:Key="redButtonStyle">
<Setter Property="Background" Value="red"/>
</Style>
</Page.Resources>
</Page>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Style redButtonStyle = (Style)this.Resources["redButtonStyle"];
}
}
MainPage::MainPage()
{
InitializeComponent();
Windows::UI::Xaml::Style style = Resources().TryLookup(winrt::box_value(L"redButtonStyle")).as<Windows::UI::Xaml::Style>();
}
Para procurar recursos de todo o aplicativo a partir do código, use Application.Current.Resources para obter o dicionário de recursos do aplicativo, conforme mostrado aqui.
<Application
x:Class="MSDNSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SpiderMSDN">
<Application.Resources>
<Style TargetType="Button" x:Key="appButtonStyle">
<Setter Property="Background" Value="red"/>
</Style>
</Application.Resources>
</Application>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Style appButtonStyle = (Style)Application.Current.Resources["appButtonStyle"];
}
}
MainPage::MainPage()
{
InitializeComponent();
Windows::UI::Xaml::Style style = Application::Current().Resources()
.TryLookup(winrt::box_value(L"appButtonStyle"))
.as<Windows::UI::Xaml::Style>();
}
Você também pode adicionar um recurso de aplicativo em código.
Há duas coisas a se ter em mente ao fazer isso.
- Primeiro, você precisa adicionar os recursos antes que qualquer página tente usar o recurso.
- Em segundo lugar, você não pode adicionar recursos no construtor do aplicativo.
Você poderá evitar os dois problemas se adicionar o recurso no método Application.OnLaunched, desta forma.
// App.xaml.cs
sealed partial class App : Application
{
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
SolidColorBrush brush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 255, 0)); // green
this.Resources["brush"] = brush;
// … Other code that VS generates for you …
}
}
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
Frame rootFrame{ nullptr };
auto content = Window::Current().Content();
if (content)
{
rootFrame = content.try_as<Frame>();
}
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
Windows::UI::Xaml::Media::SolidColorBrush brush{ Windows::UI::ColorHelper::FromArgb(255, 0, 255, 0) };
Resources().Insert(winrt::box_value(L"brush"), winrt::box_value(brush));
// … Other code that VS generates for you …
Cada FrameworkElement pode ter um ResourceDictionary
FrameworkElement é uma classe base da qual os controles herdam e tem uma propriedade Resources. Assim, você pode adicionar um dicionário de recursos locais a qualquer FrameworkElement.
Aqui, tanto Page quanto Border têm dicionários de recursos, e ambas têm um recurso chamado "greeting". O TextBlock chamado “textBlock2” está dentro de Border e, portanto, sua pesquisa de recursos examina primeiro os recursos de Border, depois os recursos de Page e depois os recursos de Application. O TextBlock lerá “Hola mundo”.
Para acessar os recursos desse elemento no código, use a propriedade Recursos do elemento. O acesso aos recursos de um FrameworkElement no código, em vez de XAML, examinará apenas esse dicionário, não os dicionários do elemento pai.
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:String x:Key="greeting">Hello world</x:String>
</Page.Resources>
<StackPanel>
<!-- Displays "Hello world" -->
<TextBlock x:Name="textBlock1" Text="{StaticResource greeting}"/>
<Border x:Name="border">
<Border.Resources>
<x:String x:Key="greeting">Hola mundo</x:String>
</Border.Resources>
<!-- Displays "Hola mundo" -->
<TextBlock x:Name="textBlock2" Text="{StaticResource greeting}"/>
</Border>
<!-- Displays "Hola mundo", set in code. -->
<TextBlock x:Name="textBlock3"/>
</StackPanel>
</Page>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
textBlock3.Text = (string)border.Resources["greeting"];
}
}
MainPage::MainPage()
{
InitializeComponent();
textBlock3().Text(unbox_value<hstring>(border().Resources().TryLookup(winrt::box_value(L"greeting"))));
}
Dicionários de recursos mesclados
Um dicionário de recursos mesclado combina um dicionário de recursos em outro, geralmente em outro arquivo.
Dica Você pode criar um arquivo de dicionário de recursos no Microsoft Visual Studio usando a opção Adicionar > Novo Item…> Dicionário de Recursos do menu Projeto.
Aqui, você define um dicionário de recursos em um arquivo XAML separado chamado Dictionary1.xaml.
<!-- Dictionary1.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MSDNSample">
<SolidColorBrush x:Key="brush" Color="Red"/>
</ResourceDictionary>
Para usar esse dicionário, mescle-o com o dicionário da sua página:
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
<x:String x:Key="greeting">Hello world</x:String>
</ResourceDictionary>
</Page.Resources>
<TextBlock Foreground="{StaticResource brush}" Text="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>
Veja o que acontece neste exemplo. Em <Page.Resources>
, você declara <ResourceDictionary>
. A estrutura XAML cria implicitamente um dicionário de recursos para você quando você adiciona recursos ao <Page.Resources>
, no entanto, nesse caso, você não quer qualquer dicionário de recursos, você quer um que contenha dicionários mesclados.
Então você declara <ResourceDictionary>
, em seguida, adicionar coisas à sua coleção <ResourceDictionary.MergedDictionaries>
. Cada uma dessas entradas assume a forma <ResourceDictionary Source="Dictionary1.xaml"/>
. Para adicionar mais de um dicionário, basta adicionar uma entrada <ResourceDictionary Source="Dictionary2.xaml"/>
após a primeira entrada.
Depois de <ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries>
, você pode, opcionalmente, colocar recursos adicionais em seu dicionário principal. Você usa recursos de um dicionário mesclado como um dicionário normal. No exemplo acima, {StaticResource brush}
localiza o recurso no dicionário filho/mesclado (Dictionary1.xaml), enquanto {StaticResource greeting}
localiza seu recurso no dicionário da página principal.
Na sequência de pesquisa de recursos, um dicionário MergedDictionaries só é verificado após a verificação de todos os recursos com chave do ResourceDictionary. Depois de pesquisar esse nível, a pesquisa chega aos dicionários mesclados e cada item em MergedDictionaries é verificado. Se existirem vários dicionários mesclados, esses dicionários serão verificados no sentido inverso da ordem em que são declarados na propriedade MergedDictionaries. No exemplo a seguir, se Dictionary2.xaml e Dictionary1.xaml declararam a mesma chave, a chave de Dictionary2.xaml será usada primeiro porque é a última no conjunto MergedDictionaries.
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
<ResourceDictionary Source="Dictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<TextBlock Foreground="{StaticResource brush}" Text="greetings!" VerticalAlignment="Center"/>
</Page>
No escopo de qualquer ResourceDictionary, o dicionário é verificado para confirmar a exclusividade da chave. Entretanto, esse escopo não se estende pelos vários itens em arquivos diferentes de MergedDictionaries.
É possível usar a combinação da sequência de pesquisa e a ausência de imposição de chave exclusiva nos escopos de dicionários mesclados para criar uma sequência de valores de fallback dos recursos do ResourceDictionary. Por exemplo, você pode armazenar as preferências do usuário para uma cor de pincel específica no último dicionário de recursos mesclado na sequência, usando um dicionário de recursos que sincroniza com o estado do aplicativo e os dados de preferência do usuário. No entanto, se não houver nenhuma preferência de usuário, você poderá definir essa mesma cadeia de caracteres de chave para um recurso ResourceDictionary no arquivo MergedDictionaries inicial e isso pode servir como o valor de fallback. Lembre-se de que qualquer valor fornecido em um dicionário de recursos primários é sempre verificado antes que os dicionários mesclados sejam verificados, portanto, se você quiser usar a técnica de fallback, não defina esse recurso em um dicionário de recursos primário.
Recursos e dicionários de tema
Um ThemeResource é semelhante a um StaticResource, mas a pesquisa de recursos é reavaliada quando o tema é alterado.
Neste exemplo, você define o primeiro plano de um TextBlock como um valor do tema atual.
<TextBlock Text="hello world" Foreground="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" VerticalAlignment="Center"/>
Um dicionário de tema é um tipo especial de dicionário mesclado que contém os recursos que variam de acordo com o tema que um usuário está usando atualmente em seu dispositivo. Por exemplo, o tema “claro” pode usar um pincel de cor branca, enquanto o tema “escuro” pode usar um pincel de cor escura. O pincel altera o recurso para o qual ele resolve, mas, caso contrário, a composição de um controle que usa o pincel como um recurso pode ser a mesma. Para reproduzir o comportamento de alternância de temas em seus próprios modelos e estilos, em vez de usar MergedDictionaries como a propriedade para mesclar os itens nos dicionários principais, use a propriedade ThemeDictionaries.
Cada elemento ResourceDictionary dentro de ThemeDictionaries deve ter um valor x:Key. O valor é uma cadeia de caracteres que nomeia o tema relevante, por exemplo, “padrão”, “escuro”, “claro” ou “alto contraste”. Normalmente, Dictionary1
e Dictionary2
definirão recursos que têm os mesmos nomes, mas valores diferentes.
Aqui, você usa texto vermelho para o tema claro e texto azul para o tema escuro.
<!-- Dictionary1.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MSDNSample">
<SolidColorBrush x:Key="brush" Color="Red"/>
</ResourceDictionary>
<!-- Dictionary2.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MSDNSample">
<SolidColorBrush x:Key="brush" Color="blue"/>
</ResourceDictionary>
Neste exemplo, você define o primeiro plano de um TextBlock como um valor do tema atual.
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" x:Key="Light"/>
<ResourceDictionary Source="Dictionary2.xaml" x:Key="Dark"/>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Page.Resources>
<TextBlock Foreground="{StaticResource brush}" Text="hello world" VerticalAlignment="Center"/>
</Page>
Para dicionários de tema, o dicionário ativo a ser usado para pesquisa de recursos muda dinamicamente, sempre que a extensão de marcação ThemeResource é usada para fazer a referência e o sistema detecta uma alteração de tema. O comportamento de pesquisa feito pelo sistema é baseado no mapeamento do tema ativo para a x:Key de um dicionário de tema específico.
Pode ser útil examinar a maneira como os dicionários de tema são estruturados nos recursos de design XAML padrão, que fazem paralelo com os modelos que o Windows Runtime usa por padrão para seus controles. Abra os arquivos XAML em \(Arquivos de Programas)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<versão do SDK>\Generic usando um editor de texto ou seu IDE. Observe como os dicionários de tema são definidos primeiro em generic.xaml e como cada dicionário de tema define as mesmas chaves. Cada chave é então referenciada por elementos de composição nos vários elementos chaveados que estão fora dos dicionários de tema e definidos posteriormente no XAML. Há também um arquivo themeresources.xaml separado para design que contém apenas os recursos de tema e modelos extras, não os modelos de controle padrão. As áreas de tema são duplicatas do que você veria em generic.xaml.
Quando você usa ferramentas de design XAML para editar cópias de estilos e modelos, as ferramentas de design extraem seções dos dicionários de recursos de design XAML e as colocam como cópias locais de elementos de dicionário XAML que fazem parte de seu aplicativo e projeto.
Para saber mais e obter uma lista dos recursos do sistema e dos recursos específicos de temas que estão disponíveis para o seu aplicativo, confira Recursos de temas XAML.
Comportamento de pesquisa para referências de recursos XAML
Comportamento de pesquisa é o termo que descreve como o sistema de recursos XAML tenta localizar um recurso XAML. A pesquisa ocorre quando uma chave é referenciada como uma referência de recurso XAML de algum lugar no XAML do aplicativo. Primeiro, o sistema de recursos tem um comportamento previsível para onde ele verificará a existência de um recurso com base no escopo. Se um recurso não for encontrado no escopo inicial, o escopo será expandido. O comportamento de pesquisa continua em todos os locais e escopos que um recurso XAML poderia ser definido por um aplicativo ou pelo sistema. Se todas as possíveis tentativas de pesquisa de recursos falharem, geralmente ocorrerá um erro. Normalmente, é possível eliminar esses erros durante o processo de desenvolvimento.
O comportamento de pesquisa para referências de recursos XAML começa com o objeto em que o uso real foi aplicado e sua respectiva propriedade Resources. Se houver um ResourceDictionary nesse local, esse ResourceDictionary será verificado para obter um item que tenha a chave solicitada. Esse primeiro nível de pesquisa raramente é relevante porque você geralmente não define e faz referência a um recurso no mesmo objeto. Na verdade, uma propriedade Resources muitas vezes não existe aqui. É possível fazer referências a recursos XAML praticamente de qualquer lugar do XAML; você não está limitado às propriedades de subclasses FrameworkElement.
A sequência de pesquisa, em seguida, verifica o próximo objeto pai na árvore de objetos de runtime do aplicativo. Se FrameworkElement.Resources existir e contiver um ResourceDictionary, o item de dicionário com a cadeia de caracteres da chave especificada será solicitado. Se o recurso for encontrado, a sequência de pesquisa será interrompida e o objeto será fornecido ao local onde a referência foi feita. Caso contrário, o comportamento de pesquisa avança para o próximo nível pai em direção à raiz da árvore de objetos. A pesquisa pros recursivamente até que o elemento raiz do XAML seja alcançado, esgotando a pesquisa de todos os possíveis locais de recursos imediatos.
Observação
É prática comum definir todos os recursos imediatos no nível da raiz de uma página, tanto para obter as vantagens desse comportamento de pesquisa de recursos como também como uma convenção do estilo de marcação XAML.
Se o recurso solicitado não for encontrado nos recursos imediatos, a próxima etapa de pesquisa será verificar a propriedade Application.Resources. Application.Resources é o melhor lugar para colocar quaisquer recursos específicos do aplicativo que são referenciados por várias páginas na estrutura de navegação do seu aplicativo.
Importante
A ordem dos recursos adicionados a um ResourceDictionary afeta a ordem em que eles serão aplicados. O dicionário XamlControlsResources
substitui várias chaves de recurso padrão. Portanto, deve ser adicionado a Application.Resources
primeiro, para que não substitua outros estilos ou recursos personalizados no aplicativo.
Os modelos de controle têm outro local possível na pesquisa de referência: dicionários de tema. Um dicionário de temas é um único arquivo XAML que tem o elemento ResourceDictionary como raiz. O dicionário de temas pode ser um dicionário mesclado de Application.Resources. O dicionário de tema também pode ser o dicionário de tema específico de controle para um controle personalizado de modelo.
Finalmente, há uma pesquisa de recursos em relação aos recursos da plataforma. Os recursos da plataforma incluem os modelos de controle definidos para cada um dos temas da interface do usuário do sistema e que definem a aparência padrão de todos os controles que você usa para a interface do usuário em um aplicativo do Windows Runtime. Os recursos da plataforma também incluem um conjunto de recursos nomeados relacionados à aparência e aos temas de todo o sistema. Esses recursos são tecnicamente um item MergedDictionaries e estão disponíveis para pesquisa de XAML ou código depois que o aplicativo é carregado. Por exemplo, os recursos de tema do sistema incluem um recurso chamado "SystemColorWindowTextColor" que oferece uma definição de Color para combinar a cor do texto do aplicativo com a cor do texto da janela do sistema que vem do sistema operacional e das preferências do usuário. Outros estilos XAML para seu aplicativo podem se referir a esse estilo ou seu código pode obter um valor de pesquisa de recurso (e convertê-lo em Cor no caso de exemplo).
Para saber mais e obter uma lista dos recursos do sistema e dos recursos específicos de temas que estão disponíveis para um aplicativo do Windows em XAML, confira Recursos de temas XAML.
Se a chave solicitada ainda não for encontrada em nenhum desses locais, ocorrerá um erro/exceção de análise XAML. Em determinadas circunstâncias, a exceção de análise XAML pode ser uma exceção em tempo de execução que não é detectada por uma ação de compilação de marcação XAML ou por um ambiente de design XAML.
Devido ao comportamento de pesquisa em camadas para dicionários de recursos, você pode definir deliberadamente vários itens de recurso que tenham o mesmo valor de cadeia de caracteres que a chave, desde que cada recurso seja definido em um nível diferente. Ou seja, embora as chaves devam ser exclusivas em qualquer ResourceDictionary fornecido, a exigência de exclusividade não se estende à sequência do comportamento de pesquisa como um todo. Durante a pesquisa, somente o primeiro objeto recuperado com êxito é usado para a referência de recurso XAML e, em seguida, a pesquisa é interrompida. Você pode usar esse comportamento para solicitar o mesmo recurso XAML por chave em várias posições dentro do XAML do seu aplicativo, mas obter recursos diferentes de volta, dependendo do escopo a partir do qual a referência de recurso XAML foi feita e como essa pesquisa específica se comporta.
Encaminhar referências em um ResourceDictionary
As referências de recursos XAML em um dicionário de recursos específico devem referenciar um recurso que já foi definido com uma chave e esse recurso deve aparecer lexicalmente antes da referência ao recurso. As referências de encaminhamento não podem ser resolvidas por uma referência de recursos XAML. Por esse motivo, se você usar referências de recursos XAML de dentro de outro recurso, deverá projetar sua estrutura de dicionário de recursos para que os recursos usados por outros recursos sejam definidos primeiro em um dicionário de recursos.
Os recursos definidos no nível do aplicativo não podem fazer referências a recursos imediatos. Isso equivale a tentar uma referência direta, porque os recursos do aplicativo são realmente processados primeiro (quando o aplicativo é iniciado pela primeira vez e antes que qualquer conteúdo da página de navegação seja carregado). No entanto, qualquer recurso imediato pode fazer uma referência a um recurso de aplicativo, e isso pode ser uma técnica útil para evitar situações de referência direta.
Os recursos XAML devem ser compartilháveis
Para que um objeto exista em um ResourceDictionary, esse objeto deve ser compartilhável.
Ser compartilhável é necessário porque, quando a árvore de objetos de um aplicativo é construída e usada em tempo de execução, os objetos não podem existir em vários locais na árvore. Internamente, o sistema de recursos cria cópias de valores de recurso para usar no gráfico de objeto do seu aplicativo quando cada recurso XAML é solicitado.
Um ResourceDictionary e a XAML do Windows Runtime em geral dão suporte a esses objetos para uso compartilhável:
- Estilos e modelos (Style e classes derivadas de FrameworkTemplate)
- Pincéis e cores (classes derivadas de valores Brush e Color)
- Tipos de animação, incluindo Storyboard
- Transformações (classes derivadas de GeneralTransform)
- Matrix e Matrix3D
- Valores Point
- Determinadas estruturas relacionadas à interface do usuário, como Thickness e CornerRadius
- Tipos de dados XAML intrínsecos
Você também pode usar tipos personalizados como um recurso compartilhável se seguir os padrões de implementação necessários. Você define essas classes em seu código de suporte (ou em componentes de runtime que você inclui) e, em seguida, instancia essas classes em XAML como um recurso. Exemplos: fontes de dados de objeto e implementações IValueConverter para vinculação de dados.
Os tipos personalizados devem ter um construtor padrão, porque é isso que um analisador XAML usa para instanciar uma classe. Os tipos personalizados usados como recursos não podem ter a classe UIElement em sua herança, pois o UIElement nunca pode ser compartilhável (é sempre destinado a representar exatamente um elemento da interface do usuário que existe em uma posição no gráfico de objeto do aplicativo em runtime).
Escopo de uso do UserControl
Um elemento UserControl apresenta uma situação especial de comportamento de pesquisa de recursos, pois tem os conceitos inerentes ao escopo de definição e ao escopo de uso. Um UserControl que faz uma referência de recurso XAML a partir de seu escopo de definição deve ser capaz de dar suporte à pesquisa desse recurso em sua própria sequência de pesquisa de escopo de definição, ou seja, ele não pode acessar recursos do aplicativo. No escopo de uso de um UserControl, uma referência de recurso é tratada como estando dentro da sequência de pesquisa em direção à raiz da página de uso (assim como qualquer outra referência de recurso feita a partir de um objeto em uma árvore de objetos carregada) e pode acessar recursos do aplicativo.
ResourceDictionary e XamlReader.Load
O ResourceDictionary pode ser usado na raiz ou como parte da entrada XAML do método XamlReader.Load. Você também pode incluir referências de recursos XAML nesse XAML se todas essas referências forem completamente independentes no XAML enviado para carregamento. XamlReader.Load analisa a XAML em um contexto que não reconhece nenhum outro objeto de ResourceDictionary, nem mesmo Application.Resources. Além disso, não use {ThemeResource}
de dentro do XAML enviado para XamlReader.Load.
Usando um ResourceDictionary a partir do código
A maior parte dos cenários de um ResourceDictionary é manipulada exclusivamente na XAML. Você declara o contêiner ResourceDictionary e os recursos dentro como um arquivo XAML ou conjunto de nós XAML em um arquivo de definição de interface do usuário. E, em seguida, use referências de recursos XAML para solicitar esses recursos de outras partes do XAML. Ainda assim, há determinados cenários em que seu aplicativo pode querer ajustar o conteúdo de um ResourceDictionary usando código que é executado enquanto o aplicativo está em execução ou, pelo menos, consultar o conteúdo de um ResourceDictionary para ver se um recurso já está definido. Essas chamadas de código são feitas em uma instância de ResourceDictionary, portanto, recupere primeiro uma delas seja um ResourceDictionary imediato, em algum lugar da árvore de objetos obtendo FrameworkElement.Resources ou Application.Current.Resources
.
No código de C# ou do Microsoft Visual Basic, você pode referenciar um recurso de um determinado ResourceDictionary usando o indexador (Item). Um ResourceDictionary é um dicionário de cadeia de caracteres com chave, portanto, o indexador usa a chave de cadeia de caracteres em vez de um índice inteiro. No código de extensões de componentes Visual C++ (C++/CX), use Lookup.
Ao usar um código para examinar ou mudar um ResourceDictionary, o comportamento para APIs como Lookup ou Item não passa de recursos imediatos para recursos do aplicativo, o que é um comportamento do analisador de XAML que só acontece enquanto páginas XAML são carregadas. Em tempo de execução, o escopo das chaves é autossuficiente para a instância ResourceDictionary que você está usando no momento. Entretanto, esse escopo não se estende em MergedDictionaries.
Além disso, se você solicitar uma chave não existente no ResourceDictionary, talvez não ocorra nenhum erro; o valor de retorno poderá simplesmente ser fornecido como null. Você ainda pode receber um erro, no entanto, se você tentar usar o null retornado como um valor. O erro viria do setter da propriedade, não da sua chamada ResourceDictionary. A única maneira de evitar um erro é se a propriedade aceitar null como um valor válido. Observe como esse comportamento contrasta com o comportamento de pesquisa XAML no tempo de análise XAML. Uma falha em resolver a chave fornecida do XAML em tempo de análise resulta em um erro de análise XAML, mesmo nos casos em que a propriedade poderia ter aceitado null.
Os dicionários de recursos mesclados são incluídos no escopo de índice do dicionário de recursos primário que faz referência ao dicionário mesclado em tempo de execução. Em outras palavras, você pode usar Item ou Lookup do dicionário principal para localizar qualquer objeto que na verdade foi definido no dicionário mesclado. Nesse caso, o comportamento de pesquisa se assemelha ao comportamento de pesquisa XAML em tempo de análise: se houver vários objetos em dicionários mesclados que tenham a mesma chave, o objeto do dicionário adicionado por último será retornado.
É possível adicionar itens a um ResourceDictionary existente chamando Add (C# ou Visual Basic) ou Insert (C++/CX). Você pode adicionar os itens a recursos imediatos ou recursos do aplicativo. Qualquer uma dessas chamadas de API requer uma chave, que satisfaz o requisito de que cada item em um ResourceDictionary deve ter uma chave. No entanto, os itens que você adiciona a um ResourceDictionary em tempo de execução não são relevantes para referências de recursos XAML. A pesquisa necessária para referências de recursos XAML acontece quando esse XAML é analisado pela primeira vez à medida que o aplicativo é carregado (ou uma alteração de tema é detectada). Os recursos adicionados às coleções em tempo de execução não estavam disponíveis na época, e alterar o ResourceDictionary não invalida um recurso já recuperado dele, mesmo se você alterar o valor desse recurso.
Também é possível remover itens de um ResourceDictionary em tempo de execução, fazer cópias parcial ou total dos itens ou executar outras operações. A listagem de membros para ResourceDictionary indica quais APIs estão disponíveis. Observe que como o ResourceDictionary tem uma API projetada para dar suporte a suas interfaces de coleção adjacentes, as opções da sua API são diferentes, dependendo de você estar usando C# ou Visual Basic, em vez de C++/CX.
ResourceDictionary e localização
Um ResourceDictionary XAML pode, inicialmente, conter cadeias de caracteres que podem ser localizadas. Em caso afirmativo, armazene essas cadeias de caracteres como recursos de projeto em vez de em um ResourceDictionary. Retire as cadeias de caracteres do XAML e, em vez disso, dê ao elemento proprietário um valor de diretiva x:Uid. Em seguida, defina um recurso em um arquivo de recursos. Forneça um nome de recurso no formato XUIDValue.PropertyName e um valor de recurso da cadeia de caracteres que deve ser localizada.
Pesquisa de recursos personalizados
Para cenários avançados, você pode implementar uma classe que pode ter um comportamento diferente do comportamento de pesquisa de referência de recurso XAML descrito neste tópico. Para fazer isso, implemente a classe CustomXamlResourceLoader para poder acessar esse comportamento usando a extensão de marcação CustomResource markup extension para referências de recursos, em vez de usar StaticResource ou ThemeResource. A maioria dos aplicativos não terá cenários que exijam isso. Para saber mais, consulte CustomXamlResourceLoader.
Tópicos relacionados
- ResourceDictionary
- Visão geral do XAML
- Extensão de marcação StaticResource
- Extensão de marcação ThemeResource
- Recursos de temas XAML
- Aplicando estilos a controles
- Atributo x:Key
Windows developer