Compartir a través de


Diccionarios de recursos

.NET Multi-platform App UI (.NET MAUI) ResourceDictionary es un repositorio para los recursos que usa una aplicación .NET MAUI. Los recursos típicos que se almacenan en ResourceDictionary incluyen estilos, plantillas de control, plantillas de datos, convertidores y colores.

Se puede hacer referencia a los recursos XAML almacenados en ResourceDictionary y aplicarlos a 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.

Sugerencia

En Visual Studio, un archivo ResourceDictionary basado en XAML respaldado por un archivo de código subyacente se puede agregar al proyecto mediante la plantilla de elemento .NET MAUI ResourceDictionary (XAML).

Crear recursos

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 .NET MAUI solo puede contener una sola clase que deriva de Application, pero a menudo hace uso de muchas clases que derivan de VisualElement, incluidas páginas, diseños y vistas. 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 ResourceDictionary adjunto a una vista, como Button o Label, solo se pueden aplicar a ese objeto en particular.
  • Los recursos de ResourceDictionary adjunto a un diseño, como StackLayout o Grid, 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 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://schemas.microsoft.com/dotnet/2021/maui"
             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>

        <!-- Images -->
        <x:String x:Key="BackgroundImage">background</x:String>
        <x:String x:Key="MenuIcon">menu.png</x:String>
        <x:String x:Key="SearchIcon">search.png</x:String>

        <!-- Implicit styles -->
        <Style TargetType="NavigationPage">
            <Setter Property="BarBackgroundColor"
                    Value="{StaticResource NavigationBarColor}" />
            <Setter Property="BarTextColor"
                    Value="{StaticResource NavigationBarTextColor}" />
        </Style>

        <Style TargetType="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 implícitos Style.

Importante

La inserción de recursos directamente entre las etiquetas de elemento de propiedad Resources crea automáticamente un objeto ResourceDictionary. Sin embargo, también es válido colocar todos los recursos entre etiquetas opcionales ResourceDictionary.

Consumo de recursos

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 de ResourceDictionary con la extensión de marcado XAML 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, consulta Extensiones de marcado XAML.

En el ejemplo XAML siguiente se muestra cómo consumir recursos y también definir un recurso adicional en StackLayout.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ResourceDictionaryDemo.MainPage"
             Title="Main page">
    <StackLayout Margin="{StaticResource PageMargin}"
                 Spacing="6">
        <StackLayout.Resources>
            <!-- Implicit style -->
            <Style TargetType="Button">
                <Setter Property="FontSize" Value="14" />
                <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:

Consuming resource dictionary resources.

Importante

Los recursos que son específicos de una página no deberían incluirse en el diccionario de recursos a nivel de aplicación, dado que los recursos se analizarán en el inicio de la aplicación en lugar de cuando los solicite una página. Para más información, consulte Reducción del tamaño del diccionario de recursos de 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 no se encuentra la clave, se genera 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 vista o diseño.

diccionarios de recursos independientes

También se puede crear ResourceDictionary como un archivo XAML independiente que no está respaldado por un archivo de código subyacente. Para crear un archivo ResourceDictionary independiente, agrega un nuevo archivo ResourceDictionary al proyecto con la plantilla del elemento .NET MAUI ResourceDictionary (XAML) y elimina su archivo de código subyacente. Después, en el archivo XAML, quita el atributo x:Class de la etiqueta ResourceDictionary cerca del principio del archivo. Además, agrega <?xaml-comp compile="true" ?> después del encabezado XML para asegurarte de que se compilará el XAML.

Nota:

Un ResourceDictionary independiente debe tener una acción de compilación de MauiXaml.

En el ejemplo de XAML siguiente se muestra un elemento ResourceDictionary independiente denominado MyResourceDictionary.xaml:

<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
    <DataTemplate x:Key="PersonDataTemplate">
        <ViewCell>
            <Grid RowSpacing="6"
                  ColumnSpacing="6">
                <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.

Combinar diccionarios de recursos

Los diccionarios de recursos se pueden combinar combinando uno o varios objetos ResourceDictionary en otro 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 ResourceDictionary.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 ResourceDictionary tenga una acción de compilación establecida en en MauiXaml, tenga un archivo de código subyacente y defina 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:DefaultTheme />
                <!-- 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, .NET MAUI usa la siguiente prioridad de recursos:

  1. Los recursos locales para el diccionario de recursos.
  2. 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 propiedad MergedDictionaries.

Sugerencia

La búsqueda de diccionarios de recursos puede ser una tarea intensiva desde el punto de vista computacional si una aplicación contiene varios diccionarios de recursos de gran tamaño. 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.

Consumo de un diccionario de recursos basado en XAML a partir de código

Los diccionarios de recursos definidos en XAML se pueden consumir en código, siempre que el objeto ResourceDictionary esté respaldado por un archivo de código subyacente. En Visual Studio, los archivos ResourceDictionary basados en XAML respaldados por archivos de código subyacente se pueden agregar al proyecto mediante la plantilla de elemento ResourceDictionary (XAML) de .NET MAUI:

Screenshot of resource dictionaries backed by code-behind.

Los diccionarios de recursos basados en XAML respaldados por archivos de código subyacente se pueden consumir desde C# agregándolos a la colección MergedDictionaries del diccionario de recursos:

Resources.MergedDictionaries.Add(new MyMauiApp.Resources.Styles.MyColors());
Resources.MergedDictionaries.Add(new MyMauiApp.Resources.Styles.MyStyles());

Acceso a los recursos por clave desde código

Puedes acceder a los recursos de un diccionario de recursos desde código como cualquier otro diccionario.

En el ejemplo siguiente se muestra cómo recuperar y aplicar un recurso desde el diccionario de recursos de una página:

// Retrieve the Primary color value which is in the page's resource dictionary
var hasValue = Resources.TryGetValue("Primary", out object primaryColor);

if (hasValue)
{
    myLabel.TextColor = (Color)primaryColor;
}

Este es el enfoque recomendado que garantiza que .NET MAUI no inicie KeyNotFoundException si no puede recuperar un recurso del código. Esto puede ocurrir cuando un diccionario de recursos combinado se compone de recursos definidos en un archivo XAML y recursos insertados. Para más información, vea el problema de GitHub n.º 11214.

Nota:

Para recuperar los recursos de toda la aplicación del código, accede al diccionario de recursos App.Current.Resources.