Diccionarios de recursos de Xamarin.Forms
Un elemento ResourceDictionary
es un repositorio para los recursos que usa una aplicación de Xamarin.Forms. Los recursos típicos que se almacenan en un elemento ResourceDictionary
incluyen estilos, plantillas de control, plantillas de datos, colores y convertidores.
En XAML, se puede hacer referencia a los recursos almacenados en un elemento ResourceDictionary
y aplicarlos a los elementos mediante la extensión de marcado StaticResource
o DynamicResource
. En C#, los recursos también se pueden definir en ResourceDictionary
y, a continuación, hacer referencia y aplicar a los elementos mediante un indexador basado en cadenas. Sin embargo, hay pocas ventajas por usar un elemento ResourceDictionary
en C#, ya que los objetos compartidos se pueden almacenar como campos o propiedades, y se accede directamente sin tener que recuperarlos primero de un diccionario.
Creación de recursos en XAML
Cada objeto derivado VisualElement
tiene una propiedad Resources
, que es ResourceDictionary
que puede contener recursos. Del mismo modo, un objeto derivado Application
tiene una propiedad Resources
, que es ResourceDictionary
que puede contener recursos.
Una aplicación de Xamarin.Forms solo contiene una clase que deriva de Application
, pero a menudo usa muchas clases que derivan de VisualElement
, incluidas páginas, diseños y controles. Cualquiera de estos objetos puede tener su propiedad Resources
establecida en un recurso contenedor ResourceDictionary
. Elegir dónde colocar un ResourceDictionary
determinado afecta dónde se pueden usar los recursos:
- Los recursos de un elemento
ResourceDictionary
que se adjuntan a una vista comoButton
oLabel
solo se pueden aplicar a ese objeto determinado. - Los recursos de un elemento
ResourceDictionary
adjuntos a un diseño comoStackLayout
oGrid
se pueden aplicar al diseño y a todos los elementos secundarios de ese diseño. - Los recursos de
ResourceDictionary
definidos en el nivel de página se pueden aplicar a la página y a sus elementos secundarios. - Los recursos de un elemento
ResourceDictionary
definidos en el nivel de aplicación se pueden aplicar en toda la aplicación.
A excepción de los estilos implícitos, cada recurso del diccionario de recursos debe tener una clave de cadena única definida con el atributo x:Key
.
En el código XAML siguiente se muestran los recursos definidos a nivel ResourceDictionary
de aplicación en el archivo 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>
En este ejemplo, el diccionario de recursos define un recurso Thickness
, varios recursos Color
y dos recursos Style
implícitos. Para obtener más información sobre la clase App
, consulte Clase App de Xamarin.Forms.
Nota:
También es válido colocar todos los recursos entre etiquetas ResourceDictionary
explícitas. Sin embargo, desde Xamarin.Forms 3.0 las etiquetas ResourceDictionary
no son obligatorias. En su lugar, el objeto ResourceDictionary
se crea automáticamente y puede insertar los recursos directamente entre las etiquetas del elemento de propiedad Resources
.
Consumo de recursos en XAML
Cada recurso tiene una clave que se especifica mediante el atributo x:Key
, que se convierte en su clave de diccionario en ResourceDictionary
. La clave se usa para hacer referencia a un recurso del elemento ResourceDictionary
con la extensión de marcado StaticResource
o DynamicResource
.
La extensión de marcado StaticResource
es similar a la extensión de marcado DynamicResource
en que ambas usan una clave de diccionario para hacer referencia a un valor de un diccionario de recursos. Sin embargo, mientras que la extensión de marcado StaticResource
realiza una búsqueda de diccionario única, la extensión de marcado DynamicResource
mantiene un vínculo a la clave de diccionario. Por lo tanto, si se reemplaza la entrada del diccionario asociada a la clave, el cambio se aplica al elemento visual. Esto permite realizar cambios en los recursos en tiempo de ejecución en una aplicación. Para obtener más información sobre las extensiones de marcado, consulte Extensiones de marcado de XAML.
En el ejemplo de XAML siguiente, se muestra cómo consumir recursos y también se definen recursos adicionales en un elemento 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>
En este ejemplo, el objeto ContentPage
consume el estilo implícito definido en el diccionario de recursos a nivel de aplicación. El objeto StackLayout
consume el recurso PageMargin
definido en el diccionario de recursos a nivel de aplicación, mientras que el objeto Button
consume el estilo implícito definido en el diccionario de recursos StackLayout
. El resultado es el aspecto que se muestra en las capturas de pantalla siguientes:
Importante
Los recursos específicos de una sola página no se deben incluir en un diccionario de recursos de nivel de aplicación, ya que dichos recursos se analizarán en el inicio de la aplicación en lugar de cuando lo requiera una página. Para obtener más información, consulte Reducción del tamaño del diccionario de recursos de la aplicación.
Comportamiento de búsqueda de recursos
El siguiente proceso de búsqueda se produce cuando se hace referencia a un recurso con la extensión de marcado StaticResource
o DynamicResource
:
- Se comprueba la clave solicitada en el diccionario de recursos, si existe, para el elemento que establece la propiedad. Si se encuentra la clave solicitada, se devuelve su valor y finaliza el proceso de búsqueda.
- Si no se encuentra una coincidencia, el proceso de búsqueda busca en el árbol visual hacia arriba y comprueba el diccionario de recursos de cada elemento primario. Si se encuentra la clave solicitada, se devuelve su valor y finaliza el proceso de búsqueda. De lo contrario, este proceso continúa hasta que se alcanza el elemento raíz.
- Si no se encuentra una coincidencia en el elemento raíz, se examina el diccionario de recursos a nivel de aplicación.
- Si todavía no se encuentra una coincidencia, se produce
XamlParseException
.
Por lo tanto, cuando el analizador XAML encuentra una extensión de marcado StaticResource
o DynamicResource
, busca una clave coincidente al desplazarse por el árbol visual, usando la primera coincidencia que encuentra. Si esta búsqueda finaliza en la página y la clave todavía no se encuentra, el analizador XAML busca ResourceDictionary
adjunto al objeto App
. Si todavía no se encuentra la clave, se produce una excepción.
Invalidar recursos
Cuando los recursos comparten claves, los recursos definidos en la parte inferior del árbol visual tendrán prioridad sobre los definidos en la parte superior. Por ejemplo,si se establece un recurso AppBackgroundColor
en AliceBlue
en el nivel de aplicación se invalidará mediante un recurso AppBackgroundColor
de nivel de página establecido en Teal
. Del mismo modo, un recurso AppBackgroundColor
de nivel de página se invalidará mediante un recurso AppBackgroundColor
de nivel de control.
diccionarios de recursos independientes
Una clase derivada de ResourceDictionary
también puede estar en un archivo XAML independiente. De este modo, el archivo XAML se puede compartir entre aplicaciones.
Para crear este tipo de archivo, agregue un nuevo elemento de vista de contenido o página de contenido al proyecto (pero no una vista de contenido o una página de contenido con solo un archivo de C#). Elimine el archivo de código subyacente y, en el archivo XAML, cambie el nombre de la clase base de ContentView
o ContentPage
a ResourceDictionary
. Además, quite el atributo x:Class
de la etiqueta raíz del archivo.
En el ejemplo de XAML siguiente, se muestra un elemento ResourceDictionary
llamado MyResourceDictionary.xaml:
<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>
En este ejemplo, ResourceDictionary
contiene un único recurso, que es un objeto de tipo DataTemplate
. MyResourceDictionary.xaml se puede consumir combinándolo en otro diccionario de recursos.
De manera predeterminada, el enlazador quitará los archivos XAML independientes de las compilaciones de versión cuando el comportamiento del enlazador esté establecido para vincular todos los ensamblados. Para asegurarse de que los archivos XAML independientes permanecen en una compilación de versión:
Agregue un atributo personalizado
Preserve
al ensamblado que contiene los archivos XAML independientes. Para obtener más información, consulte Conservación del código.Establezca el atributo
Preserve
en el nivel de ensamblado:[assembly:Preserve(AllMembers = true)]
Para obtener más información sobre la vinculación, consulte Vinculación de aplicaciones de Xamarin.iOS y Vinculación en Android.
Diccionarios de recursos combinados
Los diccionarios de recursos combinados combinan uno o varios objetos ResourceDictionary
en otro objeto ResourceDictionary
.
Combinar diccionarios de recursos locales
Un archivo ResourceDictionary
local se puede combinar en otro ResourceDictionary
creando un objeto ResourceDictionary
cuya propiedad Source
se establece en el nombre de archivo XAML con los recursos:
<ContentPage ...>
<ContentPage.Resources>
<!-- Add more resources here -->
<ResourceDictionary Source="MyResourceDictionary.xaml" />
<!-- Add more resources here -->
</ContentPage.Resources>
...
</ContentPage>
Esta sintaxis no crea una instancia de la clase MyResourceDictionary
. En su lugar, hace referencia al archivo XAML. Por este motivo, al establecer la propiedad Source
, no se requiere un archivo de código subyacente y el atributo x:Class
se puede quitar de la etiqueta raíz del archivo MyResourceDictionary.xaml.
Importante
La propiedad Source
solo se puede establecer desde XAML.
Combinar diccionarios de recursos de otros ensamblados
ResourceDictionary
también se puede combinar en otro ResourceDictionary
agregándolo a la propiedad MergedDictionaries
de ResourceDictionary
. Esta técnica permite combinar diccionarios de recursos, independientemente del ensamblado en el que residen. La combinación de diccionarios de recursos de ensamblados externos requiere que el elemento ResourceDictionary
tenga una acción de compilación establecida en EmbeddedResource, para tener un archivo de código subyacente y para definir el atributo x:Class
en la etiqueta raíz del archivo.
Advertencia
La clase ResourceDictionary
también define una propiedad MergedWith
. Pero esta propiedad ha quedado en desuso y ya no debe usarse.
En el ejemplo de código siguiente se muestran dos diccionarios de recursos que se agregan a la colección MergedDictionaries
de un nivel 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>
En este ejemplo, un diccionario de recursos del mismo ensamblado y un diccionario de recursos de un ensamblado externo se combinan en el diccionario de recursos de nivel de página. Además, también puedes agregar otros objetos ResourceDictionary
dentro de las etiquetas de elemento de propiedad MergedDictionaries
y otros recursos fuera de esas etiquetas.
Importante
Solo puede haber una etiqueta de elemento de propiedad MergedDictionaries
en un ResourceDictionary
, pero puedes colocar tantos objetos ResourceDictionary
allí como sea necesario.
Cuando los recursos ResourceDictionary
combinados comparten valores de atributo x:Key
idénticos, Xamarin.Forms usa la siguiente precedencia de recursos:
- Los recursos locales para el diccionario de recursos.
- Los recursos contenidos en los diccionarios de recursos que se combinaron a través de la colección
MergedDictionaries
, en el orden inverso en el que aparecen en la propiedadMergedDictionaries
.
Nota:
La búsqueda en diccionarios de recursos puede ser una tarea de uso intensivo de cálculo si una aplicación contiene varios diccionarios de recursos grandes. Por lo tanto, para evitar búsquedas innecesarias, asegúrate de que cada página de una aplicación solo use diccionarios de recursos adecuados para la página.
Vínculos relacionados
- Extensiones de marcado XAML
- Estilos de Xamarin.Forms
- Vinculación de aplicaciones de Xamarin.iOS
- Vincular en Android
- API ResourceDictionary