Xamarin.Forms Dicionários de recursos
A ResourceDictionary
é um repositório de recursos usados por um Xamarin.Forms aplicativo. Os recursos típicos armazenados em um ResourceDictionary
incluem estilos, modelos de controle, modelos de dados, cores e conversores.
Em XAML, os recursos armazenados em um ResourceDictionary
podem ser referenciados e aplicados a elementos usando a StaticResource
extensão de marcação or DynamicResource
. Em C#, os recursos também podem ser definidos em um ResourceDictionary
e, em seguida, referenciados e aplicados a elementos usando um indexador baseado em cadeia de caracteres. No entanto, há pouca vantagem em usar um ResourceDictionary
em C#, pois objetos compartilhados podem ser armazenados como campos ou propriedades e acessados diretamente sem precisar primeiro recuperá-los de um dicionário.
Criar recursos em XAML
Cada objeto derivado VisualElement
tem uma propriedade Resources
, que é um ResourceDictionary
que pode conter recursos. Da mesma forma, um objeto derivado Application
tem uma propriedade Resources
, que é um ResourceDictionary
que pode conter recursos.
Um Xamarin.Forms aplicativo contém apenas a classe derivada de Application
, mas geralmente usa muitas classes derivadas de VisualElement
, incluindo páginas, layouts e controles. Qualquer um desses objetos pode ter sua propriedade Resources
definida como um ResourceDictionary
com recursos. Escolhendo onde colocar um determinado ResourceDictionary
impacta onde os recursos podem ser usados:
- Os recursos em um
ResourceDictionary
que está anexado a uma exibição comoButton
ouLabel
só podem ser aplicados a esse objeto específico. - Os recursos em um
ResourceDictionary
anexado a um layout, comoStackLayout
ouGrid
podem ser aplicados ao layout e a todos os filhos desse layout. - Recursos em um
ResourceDictionary
definido no nível da página podem ser aplicados à página e seus filhos. - Os recursos em um
ResourceDictionary
definido no nível do aplicativo podem ser aplicados em todo o aplicativo.
Com exceção dos estilos implícitos, cada recurso no dicionário de recursos deve ter uma chave de cadeia de caracteres exclusiva definida com o atributo x:Key
.
O XAML a seguir mostra os recursos definidos em um ResourceDictionary
de nível de aplicativo no arquivo App.xaml:
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceDictionaryDemo.App">
<Application.Resources>
<Thickness x:Key="PageMargin">20</Thickness>
<!-- Colors -->
<Color x:Key="AppBackgroundColor">AliceBlue</Color>
<Color x:Key="NavigationBarColor">#1976D2</Color>
<Color x:Key="NavigationBarTextColor">White</Color>
<Color x:Key="NormalTextColor">Black</Color>
<!-- Implicit styles -->
<Style TargetType="{x:Type NavigationPage}">
<Setter Property="BarBackgroundColor"
Value="{StaticResource NavigationBarColor}" />
<Setter Property="BarTextColor"
Value="{StaticResource NavigationBarTextColor}" />
</Style>
<Style TargetType="{x:Type ContentPage}"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>
</Application.Resources>
</Application>
Neste exemplo, o dicionário de recursos define um Thickness
recurso, vários Color
recursos e dois recursos implícitos Style
. Para obter mais informações sobre a App
classe, consulte Xamarin.Forms Classe do aplicativo.
Observação
Também é válido colocar todos os recursos entre tags explícitas ResourceDictionary
. No entanto, desde Xamarin.Forms a versão 3.0, as ResourceDictionary
tags não são necessárias. Em vez disso, o ResourceDictionary
objeto é criado automaticamente e você pode inserir os recursos diretamente entre as Resources
tags do elemento de propriedade.
Consumir recursos em XAML
Cada recurso tem uma chave que é especificada usando o atributo x:Key
, que se torna sua chave de dicionário no ResourceDictionary
. A chave é usada para fazer referência a um recurso da ResourceDictionary
extensão com a StaticResource
marcação or DynamicResource
.
A extensão de marcação StaticResource
é semelhante à extensão de marcação DynamicResource
, pois ambas usam uma chave de dicionário para fazer referência a um valor de um dicionário de recurso. No entanto, enquanto a extensão de marcação StaticResource
executa uma única pesquisa de dicionário, a extensão de marcação DynamicResource
mantém um link para a chave de dicionário. Portanto, se a entrada do dicionário associada à chave for substituída, a alteração será aplicada ao elemento visual. Isso permite que alterações de recursos de tempo de execução sejam feitas em um aplicativo. Para obter mais informações sobre extensões de marcação, consulte Extensões de marcação XAML.
O exemplo XAML a seguir mostra como consumir recursos e também define recursos adicionais em um StackLayout
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceDictionaryDemo.HomePage"
Title="Home Page">
<StackLayout Margin="{StaticResource PageMargin}">
<StackLayout.Resources>
<!-- Implicit style -->
<Style TargetType="Button">
<Setter Property="FontSize" Value="Medium" />
<Setter Property="BackgroundColor" Value="#1976D2" />
<Setter Property="TextColor" Value="White" />
<Setter Property="CornerRadius" Value="5" />
</Style>
</StackLayout.Resources>
<Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries." />
<Button Text="Navigate"
Clicked="OnNavigateButtonClicked" />
</StackLayout>
</ContentPage>
Neste exemplo, o objeto ContentPage
consome o estilo implícito definido no dicionário de recursos no nível do aplicativo. O objeto StackLayout
consome o recurso PageMargin
definido no dicionário de recursos no nível do aplicativo, enquanto o objeto Button
consome o estilo implícito definido no dicionário de recursos StackLayout
. Isso resulta na aparência mostrada nas capturas de tela seguir:
Importante
Os recursos específicos de uma única página não devem ser incluídos em um dicionário de recursos no nível do aplicativo, pois esses recursos serão analisados na inicialização do aplicativo, em vez de quando exigido por uma página. Para obter mais informações, consulte Reduzir o tamanho do dicionário de recursos do aplicativo.
Comportamento de pesquisa de recursos
O seguinte processo de pesquisa ocorre quando um recurso é referenciado com a extensão de marcação StaticResource
ou DynamicResource
:
- A chave solicitada é verificada no dicionário de recursos, ou seja, se ela existe, para o elemento que define a propriedade. Se a chave solicitada for encontrada, seu valor será retornado e o processo de pesquisa será encerrado.
- Se uma correspondência não for encontrada, o processo de pesquisa pesquisará a árvore visual de baixo para cima, verificando o dicionário de recursos de cada elemento pai. Se a chave solicitada for encontrada, seu valor será retornado e o processo de pesquisa será encerrado. Caso contrário, o processo continua para cima até que o elemento raiz seja alcançado.
- Se uma correspondência não for encontrada no elemento raiz, o dicionário de recursos no nível do aplicativo será examinado.
- Se uma correspondência ainda não for encontrada, uma
XamlParseException
será gerada.
Portanto, quando o analisador XAML encontra uma extensão de marcação StaticResource
ou DynamicResource
, ele procura uma chave correspondente viajando pela árvore visual, usando a primeira correspondência encontrada. Se essa pesquisa terminar na página e a chave ainda não tiver sido encontrada, o analisador XAML pesquisará o ResourceDictionary
anexado ao objeto App
. Se a chave ainda não for encontrada, uma exceção será lançada.
Substituição de recursos
Quando os recursos compartilham chaves, os recursos definidos mais abaixo na árvore visual terão precedência sobre aqueles definidos mais acima. Por exemplo, a definição de um recurso AppBackgroundColor
como AliceBlue
no nível do aplicativo será substituída por um recurso de nível de página AppBackgroundColor
definido como Teal
. Da mesma forma, um recurso de nível AppBackgroundColor
de página será substituído por um recurso de nível AppBackgroundColor
de controle.
Dicionários de recursos autônomos
Uma classe derivada de ResourceDictionary
também pode estar em um arquivo XAML autônomo. O arquivo XAML pode ser compartilhado entre aplicativos.
Para criar esse arquivo, adicione um novo item de Modo de Exibição de Conteúdo ou Página de Conteúdo ao projeto (mas não um Modo de Exibição de Conteúdo ou Página de Conteúdo com apenas um arquivo C#). Exclua o arquivo code-behind e, no arquivo XAML, altere o nome da classe base de ContentView
ou ContentPage
para ResourceDictionary
. Além disso, remova o x:Class
atributo da tag raiz do arquivo.
O exemplo XAML a seguir mostra um ResourceDictionary
MyResourceDictionary.xaml nomeado:
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<DataTemplate x:Key="PersonDataTemplate">
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Name}"
TextColor="{StaticResource NormalTextColor}"
FontAttributes="Bold" />
<Label Grid.Column="1"
Text="{Binding Age}"
TextColor="{StaticResource NormalTextColor}" />
<Label Grid.Column="2"
Text="{Binding Location}"
TextColor="{StaticResource NormalTextColor}"
HorizontalTextAlignment="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ResourceDictionary>
Neste exemplo, o ResourceDictionary
contém um único recurso, que é um objeto do tipo DataTemplate
. MyResourceDictionary.xaml pode ser consumido mesclando-o em outro dicionário de recursos.
Por padrão, o vinculador removerá arquivos XAML autônomos de builds de versão quando o comportamento do vinculador for definido para vincular todos os assemblies. Para garantir que os arquivos XAML autônomos permaneçam em uma compilação de versão:
Adicione um atributo personalizado
Preserve
ao assembly que contém os arquivos XAML autônomos. Para obter mais informações, consulte Preservando código.Defina o
Preserve
atributo no nível do assembly:[assembly:Preserve(AllMembers = true)]
Para obter mais informações sobre vinculação, consulte Vinculando aplicativos Xamarin.iOS e Vinculando no Android.
Dicionários de recursos mesclados
Os dicionários de recursos mesclados combinam um ou mais ResourceDictionary
objetos em outro ResourceDictionary
.
Mesclar dicionários de recursos locais
Um arquivo local ResourceDictionary
pode ser mesclado em outro ResourceDictionary
criando um objeto ResourceDictionary
cuja propriedade Source
é definida como o nome do arquivo XAML com os recursos:
<ContentPage ...>
<ContentPage.Resources>
<!-- Add more resources here -->
<ResourceDictionary Source="MyResourceDictionary.xaml" />
<!-- Add more resources here -->
</ContentPage.Resources>
...
</ContentPage>
Essa sintaxe não instancia a classe MyResourceDictionary
. Em vez disso, ele faz referência ao arquivo XAML. Por esse motivo, ao definir a propriedade Source
, um arquivo code-behind não é necessário e o atributo x:Class
pode ser removido da marca raiz do arquivo MyResourceDictionary.xaml.
Importante
A propriedade Source
só pode ser definida a partir de XAML.
Mesclar dicionários de recursos de outros assemblies
Um ResourceDictionary
também pode ser mesclado em outro ResourceDictionary
ao adicioná-lo à propriedade MergedDictionaries
do ResourceDictionary
. Essa técnica permite que dicionários de recursos sejam mesclados, independentemente do assembly em que residem. A mesclagem de dicionários de recursos de assemblies externos requer que o ResourceDictionary
tenha uma ação de build definida como EmbeddedResource, tenha um arquivo code-behind e defina o x:Class
atributo na marca raiz do arquivo.
Aviso
A classe ResourceDictionary
também define uma propriedade MergedWith
. No entanto, essa propriedade foi preterida e não deve mais ser usada.
O exemplo de código a seguir mostra dois dicionários de recursos sendo adicionados à coleção MergedDictionaries
de um nível de página ResourceDictionary
:
<ContentPage ...
xmlns:local="clr-namespace:ResourceDictionaryDemo"
xmlns:theme="clr-namespace:MyThemes;assembly=MyThemes">
<ContentPage.Resources>
<ResourceDictionary>
<!-- Add more resources here -->
<ResourceDictionary.MergedDictionaries>
<!-- Add more resource dictionaries here -->
<local:MyResourceDictionary />
<theme:LightTheme />
<!-- Add more resource dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Add more resources here -->
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Neste exemplo, um dicionário de recursos do mesmo assembly e um dicionário de recursos de um assembly externo são mesclados no dicionário de recursos no nível da página. Além disso, você também pode adicionar outros objetos ResourceDictionary
dentro das marcas de elemento de propriedade MergedDictionaries
e outros recursos fora dessas marcas.
Importante
Pode haver apenas uma marca de elemento de propriedade MergedDictionaries
em um ResourceDictionary
, mas você pode colocar quantos objetos ResourceDictionary
forem necessários.
Quando os recursos mesclados ResourceDictionary
compartilham valores de atributo idênticos x:Key
, Xamarin.Forms o usa a seguinte precedência de recurso:
- Os recursos locais para o dicionário de recursos.
- Os recursos contidos nos dicionários de recursos que foram mesclados por meio da coleção
MergedDictionaries
, na ordem inversa são listados na propriedadeMergedDictionaries
.
Observação
A pesquisa de dicionários de recursos pode ser uma tarefa computacionalmente intensiva se um aplicativo contiver vários dicionários de recursos grandes. Portanto, para evitar pesquisas desnecessárias, você deve garantir que cada página em um aplicativo use apenas dicionários de recursos apropriados para a página.
Links relacionados
- Extensões de marcação XAML
- Xamarin.Forms Estilos
- Vinculando aplicativos Xamarin.iOS
- Vinculação no Android
- ResourceDictionary API
Vídeo relacionado
Encontre mais vídeos sobre o Xamarin no Channel 9 e no YouTube.