Referencias a ResourceDictionary y a recursos XAML

Referencias a ResourceDictionary y a recursos XAML

[ Este artículo está destinado a desarrolladores de Windows 8.x y Windows Phone 8.x que escriben aplicaciones de Windows Runtime. Si estás desarrollando para Windows 10, consulta la documentación más reciente ]

XAML define la interfaz de tu aplicación y, también, tiene una forma de definir recursos en XAML. Los recursos suelen ser definiciones de algún objeto que esperas usar más de una vez. Especificas una clave para un recurso XAML que actúe como su nombre en referencias futuras. Puedes hacer referencia a un recurso a través de una aplicación o desde cualquier página XAML de la misma. XAML de Windows en tiempo de ejecución tiene un elemento ResourceDictionary donde defines tus recursos. Después, puedes hacer referencia a tus recursos mediante una extensión de marcado StaticResource o una extensión de marcado ThemeResource.

Los elementos XAML que quizás quieras declarar con más frecuencia como recursos XAML son Style, ControlTemplate, componentes de animación y subclases de Brush. Aquí explicamos cómo definir un ResourceDictionary y recursos con clave, y cómo los recursos de XAML se relacionan con otros recursos que definas como parte de tu aplicación o paquete de la aplicación. También explicamos características avanzadas del diccionario de recursos, como MergedDictionaries y ThemeDictionaries.

Requisitos previos

Damos por hecho que conoces el marcado XAML y que has leído la introducción a XAML.

Los recursos XAML deben ser compartibles

Para que un objeto exista en un ResourceDictionary, dicho objeto debe ser compartible.

Es necesario que sean compartibles porque cuando se construye el árbol de objetos de una aplicación y se usa en tiempo de ejecución, los objetos no pueden existir en varias ubicaciones del árbol. El sistema de recursos crea copias a nivel interno de los valores de recursos que se usarán en el gráfico de objetos de la aplicación cuando se solicite cada recurso XAML.

Un ResourceDictionary y el XAML de Windows en tiempo de ejecución normalmente admiten estos objetos para compartirlos:

También puedes usar tipos personalizados como un recurso compartible si sigues los patrones de implementación necesarios. Tienes que definir estas clases en el código de respaldo (o en los componentes en tiempo de ejecución que incluyas) y, después, crear instancias de estas clases en XAML como si fueran un recurso. Algunos ejemplos son orígenes de datos de objeto e implementaciones de IValueConverter para el enlace de datos.

Los tipos personalizados deben tener un constructor predeterminado, porque eso es lo que usa un analizador XAML para crear una instancia de una clase. Los tipos personalizados que se usan como recursos no pueden tener la clase UIElement en su herencia, porque un UIElement nunca se puede compartir (siempre está destinado a representar exactamente un elemento de la interfaz de usuario que existe en una posición en el gráfico de objetos de la aplicación en tiempo de ejecución).

Claves para recursos

Los elementos de un ResourceDictionary deben tener definida una clave. Desde el punto de vista de la programación, un ResourceDictionary es realmente un diccionario. Sueles definir claves para recursos XAML mediante el atributo x:Key. Hay toda una serie de objetos que pueden ser un recurso XAML. Estos objetos no comparten ninguna propiedad común de Windows en tiempo de ejecución. Así que, para que sea posible colocar todo este rango de recursos posibles en un diccionario de recursos, el lenguaje XAML define globalmente el atributo x:Key, que se puede aplicar legalmente a cualquier elemento de objeto XAML que se encuentre en el diccionario.

x:Key se convierte en la clave del elemento de diccionario y el resto de valores en el XAML definen un objeto que es el valor del elemento de diccionario.

Los recursos para el XAML de Windows en tiempo de ejecución deben usar cadenas para sus nombres de clave. Concretamente, la cadena debe seguir las reglas de gramática de XamlName. Consulta la sección sobre "gramática de XamlName" en la página de referencia del atributo x:Key.

Si incluyes un elemento en un ResourceDictionary y no tiene una clave utilizable, se producirá un error de análisis de XAML cuando la aplicación intente buscar el elemento del recurso. Si duplicas una clave, se produce un error de análisis de XAML. Microsoft Visual Studio y su superficie de diseño XAML pueden proporcionar información en tiempo de diseño en caso de que haya problemas de definición de recursos o de referencia a recursos en tu código XAML. Sin embargo, si el diseñador XAML no puede proporcionar una advertencia, los problemas de definición de recursos de XAML podrían notificarse como errores o excepciones cuando la aplicación intente cargar el código XAML en tiempo de ejecución.

Claves implícitas para plantillas de control y estilos

Las plantillas de control y los elementos Style con una propiedad TargetType son casos especiales en los que no es necesario un valor de atributo x:Key para que existan como recurso XAML. Para estos tipos, la clave para el recurso es implícita. El valor de la clave implícita se basa en un formato de cadena del valor TargetType que se declara en la plantilla o el estilo. La lógica de control XAML usa esta clave en tiempo de ejecución como la búsqueda implícita del estilo o la plantilla que va a aplicar a un control específico. Por ejemplo, un Style que tiene un TargetType="Button" puede ser el estilo implícito de todos los controles Button de la aplicación, sin que sea necesaria una clave para la definición del recurso o una referencia StaticResource de cada Button. Para obtener más información sobre los estilos implícitos y cómo funcionan, consulta Inicio rápido: plantillas de control.

Recursos de guión gráfico

Los recursos Storyboard son otro caso especial en que un Storyboard puede existir en un ResourceDictionary sin un valor x:Key, siempre y cuando tenga el valor x:Name. Por lo general, un Storyboard no se coloca en un ResourceDictionary para reutilizarlo, porque las animaciones que este contiene ya están destinadas a propiedades específicas. En cambio, un ResourceDictionary es solo un contenedor XAML adecuado en el que colocar los diversos elementos Storyboard. Al final, harás referencia a las instancias de Storyboard por su nombre y llamarás a sus métodos Begin. Esto suele realizarse desde el código subyacente en respuesta a eventos, como Loaded, o enlazado a eventos iniciados por el usuario. Para más información, consulta el tema sobre las animaciones con guion gráfico.

Recursos inmediatos y de aplicación

Existen dos propiedades para las aplicaciones típicas que contienen los nodos ResourceDictionary donde definirás recursos XAML: FrameworkElement.Resources y Application.Resources.

FrameworkElement.Resources proporciona recursos inmediatos. Los recursos inmediatos también se suelen denominar recursos de página. En XAML, se puede usar la técnica de referencia inmediata para hacer referencia a recursos XAML en FrameworkElement.Resources desde cualquier objeto que esté conectado al mismo árbol de objetos. Esto quiere decir, básicamente, desde la misma página XAML, porque normalmente defines el valor FrameworkElement.Resources en el elemento raíz de una página XAML, donde todos los posibles elementos XAML en la página puedan encontrarlo.

Application.Resources proporciona recursos de nivel de aplicación. Los recursos definidos por Application.Resources están disponibles independientemente de qué página o interfaz de usuario esté cargada como Window.Content actual de la aplicación. Especificar recursos para la aplicación puede resultar útil si cargas diferentes páginas en Window.Content para admitir la navegación y quieres evitar duplicar los mismos recursos en cada página. Asimismo, si agregas pares clave/valor (recursos) a un ResourceDictionary en tiempo de ejecución para que las páginas cargadas más tarde puedan encontrarlos, el ámbito de la aplicación proporciona una ubicación donde dichos recursos pueden persistir durante el ciclo de vida de la aplicación.

Un tercer lugar donde los recursos pueden existir es como parte del estilo predeterminado de un control, junto con el control. Esta ubicación solo se usa para las búsquedas del recurso cuya clave es definida por el valor DefaultStyleKey del control.

Nota   No confundas los conceptos relativos a ResourceDictionary con la acción de compilación de recursos, los archivos de recursos (.resw) u otros "recursos" que se describen en el contexto de la estructuración del proyecto de código que produce un paquete de la aplicación. Para más información sobre los conceptos generales de los recursos de una aplicación, consulta la definición de recursos de una aplicación y el tema sobre cómo prepararse para la localización.
 

Referencia a recursos desde XAML

En el XAML, se hace referencia a un recurso XAML existente desde un ResourceDictionary mediante la extensión de marcado StaticResource o la extensión de marcado ThemeResource. En esta documentación, se hace referencia a ellas como referencias a recursos XAML. Para usar una referencia a recursos XAML con las extensiones de marcado, siempre se hace referencia a la propiedad que estás estableciendo con el uso de un atributo.

Este es un ejemplo de XAML. Para establecer el valor de la propiedad Background de un Button para usar un recurso estático llamado fadeBrush, primero tienes que declarar el recurso con una clave y luego hacer referencia a él por dicha clave.


<ResourceDictionary>
...
  <LinearGradientBrush x:Key="fadeBrush">
    <GradientStop Color="Red" Offset="0"/>
    <GradientStop Color="Gray" Offset="1"/>
  </LinearGradientBrush>
</ResourceDictionary>
...
 <!--XAML within a UserControl or some other root container tag that defines app UI-->
<Button Background="{StaticResource fadeBrush}" .../>


En el ejemplo anterior, las dos partes del código XAML podrían no estar en el mismo archivo XAML. El ResourceDictionary podría definirse en Application.Resources, en un archivo de diccionario de temas o en un archivo de diccionario combinado.

Usa la sintaxis de atributo de XAML para hacer referencia a un recurso XAML, aunque la propiedad que estés estableciendo suela requerir un uso de elementos de propiedad en el XAML. Por ejemplo, este es un uso de elementos de propiedad equivalente, que muestra el LinearGradientBrush definido en línea y no como un recurso de ResourceDictionary.


<Button>
  <Button.Background>
    <LinearGradientBrush>
      <GradientStop Color="Red" Offset="0"/>
      <GradientStop Color="Gray" Offset="1"/>
    </LinearGradientBrush>
  </Button.Background>
</Button>

Comportamiento de la búsqueda de referencias a recursos XAML

Comportamiento de búsqueda es el término que define cómo el sistema de recursos XAML intenta buscar un recurso XAML. Se realiza la búsqueda de una clave a la que se hace referencia como una referencia de recursos XAML desde algún lugar del XAML de la aplicación. El sistema de recursos tiene un comportamiento predecible en cuanto al lugar en el que buscará si existe un recurso según el ámbito. Si un recurso no se encuentra en el ámbito inicial, este último se expande. El comportamiento de búsqueda continúa a través de las ubicaciones y los ámbitos donde podría encontrarse un recurso XAML según la definición de una aplicación o del sistema. Si no se encuentra el recurso en todos los intentos de búsqueda posibles, se suele producir un error. Por lo general, se pueden eliminar estos errores durante el proceso de desarrollo.

El comportamiento de búsqueda para las referencias a recursos XAML comienza con el objeto al que se aplica el uso real y su propiedad Resources. Si en él existe un ResourceDictionary, se comprueba si en este ResourceDictionary hay un elemento con la clave solicitada. Este primer nivel de búsqueda rara vez es relevante porque normalmente no defines un recurso y luego haces referencia a él en el mismo objeto. De hecho, suele ocurrir que aquí no existe una propiedad Resources. Puedes hacer referencias a los recursos del XAML desde casi cualquier parte del XAML; no estás limitado a las propiedades de las subclases de FrameworkElement.

A continuación, la secuencia de búsqueda comprueba el siguiente objeto primario del árbol de objetos en tiempo de ejecución de la aplicación. Si existe un FrameworkElement.Resources y contiene un ResourceDictionary, se solicita el elemento de diccionario con la clave especificada. Si se encuentra el recurso, la secuencia de búsqueda se detiene y el objeto se proporciona a la ubicación donde se creó la referencia. En caso contrario, el comportamiento de búsqueda continúa con el siguiente nivel primario hacia la raíz del árbol de objetos. La búsqueda continúa recursivamente hacia arriba hasta llegar al elemento raíz del XAML, agotando la búsqueda de todas las ubicaciones de recursos inmediatos posibles.

Nota  Es una práctica habitual definir todos los recursos inmediatos en el nivel raíz de una página, tanto para aprovechar este comportamiento de búsqueda de recursos como por una convención de estilo de marcado del XAML.
 

Si no se encuentra el recurso solicitado en los recursos inmediatos, el siguiente paso de la búsqueda es comprobar la propiedad Application.Resources. Application.Resources es el mejor lugar para poner los recursos específicos de la aplicación a los que varias páginas de la estructura de navegación de tu aplicación hacen referencia.

Las plantillas de control tienen otra posible ubicación para la búsqueda de recursos: los diccionarios de temas. Un diccionario de temas es un único archivo XAML que tiene un elemento ResourceDictionary como raíz. El diccionario de temas podría ser un diccionario combinado de Application.Resources. El diccionario de temas también podría ser el diccionario de temas específico de un control personalizado con plantilla.

Por último, se realiza una búsqueda de recursos en los recursos de la plataforma. Los recursos de la plataforma incluyen las plantillas de control definidas para cada uno de los temas de la interfaz de usuario del sistema y que definen la apariencia predeterminada de todos los controles que usas para la interfaz de usuario en una aplicación de Windows en tiempo de ejecución. También incluyen un conjunto de recursos con nombre relacionados con la apariencia y los temas de todo el sistema. Estos recursos son técnicamente un elemento MergedDictionaries y, por lo tanto, están disponibles para la búsqueda del XAML o de código cuando la aplicación se ha cargado. Por ejemplo, entre los recursos de tema del sistema encontramos uno llamado "SystemColorWindowTextColor" que ofrece una definición de Color que permite que el color del texto de la aplicación sea el mismo que el del texto de una ventana del sistema procedente del sistema operativo y las preferencias del usuario. Otros estilos de XAML para tu aplicación pueden hacer referencia a este estilo, o tu código puede obtener un valor de búsqueda de recurso (y convertirlo en Color en el caso de ejemplo).

Para obtener más información y una lista de los recursos del sistema y específicos de temas que hay a disposición de las aplicaciones de la Tienda Windows que usan XAML, consulta Referencia a recursos de temas en XAML.

Si tampoco se encuentra la clave solicitada en ninguna de estas ubicaciones, se produce una excepción o error de análisis de XAML. En determinadas circunstancias, la excepción de análisis de XAML puede ser una excepción en tiempo de ejecución que no es detectada por una acción de compilación de marcado de XAML ni por un entorno de diseño de XAML.

Debido al comportamiento de búsqueda por niveles de los diccionarios de recursos, puedes definir deliberadamente varios elementos de recurso, cada uno de ellos con el mismo valor de cadena que la clave, siempre que cada recurso se defina en un nivel diferente. En otras palabras, aunque las claves deben ser únicas en cualquier ResourceDictionary dado, este requisito no se aplica a toda la secuencia de comportamiento de búsqueda. Durante la búsqueda, solo el primer objeto que se recupere correctamente se usará para la referencia del recurso XAML y, a continuación, se detendrá la búsqueda. Puedes usar este comportamiento para solicitar el mismo recurso XAML por clave en varias posiciones del código XAML de la aplicación y obtener resultados distintos, en función del ámbito desde el que se hizo referencia al recurso XAML y el comportamiento de esa búsqueda específica.

Diccionarios de recursos combinados

Un diccionario de recursos combinado te permite declarar el contenido de un diccionario de recursos haciendo referencia a un archivo externo, y usar los recursos definidos externamente para aumentar los recursos encontrados en una propiedad Resources. El uso de un diccionario de recursos combinado modifica dos de características de los diccionarios de recursos: la secuencia de búsqueda y los requisitos de clave única dentro de un ámbito.

Para declarar un diccionario de recursos combinado, se agrega un elemento de propiedad para la propiedad MergedDictionaries a una propiedad de ResourceDictionary existente. Puedes agregar MergedDictionaries para las propiedades FrameworkElement.Resources o Application.Resources (aunque suele ser más habitual combinarlas en Application.Resources).

Debes declarar ResourceDictionary explícitamente como un elemento de objeto para usar el elemento de propiedad ResourceDictionary.MergedDictionary que contenga. El ResourceDictionary existente puede tener otros recursos con clave además del elemento de propiedad MergedDictionaries. El contenido de un elemento de propiedad XAML MergedDictionaries incluye uno o varios elementos ResourceDictionary declarados como elementos de objeto XAML. Los elementos ResourceDictionary que representan diccionarios combinados no pueden tener otros recursos con clave como contenido. En su lugar, estos elementos ResourceDictionary deben declarar solo un atributo: Source. La manera de hacer referencia a la ubicación externa del diccionario de recursos es el valor Source.

Por ejemplo, el siguiente código XAML define un ResourceDictionary con un recurso con clave, así como una colección MergedDictionaries que hace referencia a dos archivos XAML de diccionarios de recursos distintos.


<Application.Resources>
    <ResourceDictionary>
      <!--other resources can be here-->
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="rd1.xaml" />
        <ResourceDictionary Source="rd2.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>

Puedes especificar más de un ResourceDictionary en MergedDictionaries. En la secuencia de búsqueda de recursos, un diccionario MergedDictionaries solo se comprueba después de comprobar todos los recursos con clave de ese ResourceDictionary. Después de buscar en ese nivel, la búsqueda llega a los diccionarios combinados y se compruebe cada elemento de MergedDictionaries. Si hay varios diccionarios combinados, estos se comprueban en orden inverso al que se declararon en la propiedad MergedDictionaries. En el ejemplo anterior, si "rd2.xaml" y "rd1.xaml" declaran la misma clave, primero se usa la clave de "rd2.xaml" porque es la última del conjunto de MergedDictionaries.

En el ámbito de cualquier ResourceDictionary, se comprueba que la clave del diccionario sea única. Sin embargo, ese ámbito no se extiende a los diferentes elementos de los distintos archivos de MergedDictionaries.

Puedes usar la combinación de la secuencia de búsqueda y la falta de obligatoriedad de una clave única en los ámbitos de diccionarios combinados para crear una secuencia de valores de reserva de los recursos de ResourceDictionary. Por ejemplo, podrías almacenar las preferencias de un determinado color de pincel en el diccionario de recursos combinado por última vez en la secuencia, mediante un diccionario de recursos que se sincronice con el estado de la aplicación y los datos de preferencia del usuario. Sin embargo, si aún no existen preferencias del usuario, puedes definir esa misma cadena de clave para un recurso de ResourceDictionary en el archivo MergedDictionaries inicial, y puede servir como valor de reserva. Recuerda que siempre se comprueban todos los valores que proporcionas en un diccionario de recursos principal antes de comprobar los diccionarios combinados; por lo tanto, si quieres usar la técnica de reserva, no definas ese recurso en un diccionario de recursos principal.

Diccionarios de temas

Un diccionario de temas es un tipo especial de diccionario combinado diseñado para almacenar los recursos que varían en función del tema que esté usando el usuario en su PC. Por ejemplo, el tema "claro" podría usar un pincel blanco mientras que el tema predeterminado podría usar un pincel de color oscuro. El pincel cambia el recurso en el que se resuelve, aunque la composición de un control que usa el pincel como recurso podría ser la misma. Para reproducir el comportamiento de cambio de tema en tus propias plantillas y estilos, en lugar de usar MergedDictionaries como la propiedad para combinar elementos en los diccionarios principales, mejor usa la propiedad ThemeDictionaries. Al igual que con MergedDictionaries, esta propiedad se establece mediante la sintaxis de elemento de propiedad, y su valor es uno o varios elementos de objeto de ResourceDictionary.

Cada elemento ResourceDictionary de ThemeDictionaries debe tener un valor x:Key. Ese valor es una cadena que asigna un nombre al tema correspondiente —por ejemplo, "Default", "Light" o "HighContrast".

Los elementos de ResourceDictionary contenidos pueden usar uno de los dos modelos posibles:

  • El ResourceDictionary solo tiene un atributo, Source, y ningún otro contenido. Source hace referencia a un archivo XAML diferente que solo contiene una raíz de ResourceDictionary. Después, este diccionario define los elementos con clave que son específicos del tema al que el valor x:Key asigna un nombre en el elemento ResourceDictionary especificado por Source. Normalmente, el valor Source hace referencia a un archivo XAML de la estructura de tu proyecto y del paquete de la aplicación.
  • El ResourceDictionary contiene los elementos con clave que son específicos del tema al que el valor x:Key asigna un nombre en el elemento ResourceDictionary primario.

De forma similar a los diccionarios combinados, se permite definir varias veces la misma clave en un conjunto de diccionarios de temas de la misma colección ThemeDictionaries, siempre que sea única dentro de cada unidad de ResourceDictionary. De hecho esta es la intención del diseño: cada diccionario de temas debe tener un conjunto idéntico de claves. De lo contrario, si falta una de las claves en un tema, es probable que cause un problema en la interfaz de usuario cuando el tema se cargue. A diferencia de los diccionarios combinados, no importa el orden en que se defina cada tema. Para los diccionarios de temas, el diccionario activo que se usará para la búsqueda de recursos cambia dinámicamente, siempre que se use la extensión de marcado ThemeResource para crear la referencia y el sistema detecte un cambio de tema. El comportamiento de la búsqueda realizada por el sistema se basa en la asignación del tema activo al atributo x:Key de un diccionario de temas específico.

Puede resultar útil examinar cómo se estructuran los diccionarios de temas en los recursos de diseño predeterminados del XAML, que siguen las plantillas que Windows en tiempo de ejecución usa de manera predeterminada para sus controles. Usa un editor de texto o uno similar en el IDE para abrir los archivos de XAML en \(Program Files)\Windows Kits\<version>\Include\winrt\xaml\design. Observa cómo se definen primero los diccionarios de temas en generic.xaml, y cómo cada diccionario de temas define las mismas claves. Después, los elementos de composición de los diversos elementos con clave que están fuera de los diccionarios de temas, y que se definen más adelante en el XAML, hacen referencia a cada una de estas claves. También hay un archivo themeresources.xaml independiente para el diseño que solo contiene recursos de temas y plantillas adicionales, en lugar de las plantillas de control predeterminadas. Las áreas de temas son duplicados de lo que verías en generic.xaml.

Cuando usas herramientas de diseño XAML para editar copias de estilos y plantillas, estas herramientas extraen secciones de los diccionarios de recursos de diseño XAML y las colocan como copias locales de los elementos del diccionario XAML que forman parte de la aplicación y el proyecto.

Para obtener más información y una lista de los recursos del sistema y específicos de temas que hay a disposición de las aplicaciones de la Tienda Windows que usan XAML, consulta Referencia a recursos de temas en XAML.

Comportamiento de Windows 8

Windows 8 no era compatible con la extensión de marcado ThemeResource. Esta está disponible a partir de Windows 8.1. Además, Windows 8 no admitía la conmutación dinámica de recursos relacionados por tema para una aplicación de Windows en tiempo de ejecución. La aplicación tenía que reiniciarse para elegir el cambio de tema de las plantillas y estilos de XAML. Esto no es una buena experiencia de usuario, por lo que se recomienda volver a compilar las aplicaciones para Windows 8.1, para que puedan usar estilos con usos de ThemeResource y puedan conmutar dinámicamente temas cuando lo haga el usuario. Las aplicaciones compiladas para Windows 8 que se ejecuten en Windows 8.1 siguen usando el comportamiento de Windows 8.

Referencias adelantadas en un ResourceDictionary

Las referencias a recursos XAML en un diccionario de recursos determinado deben hacer referencia a un recurso que ya haya sido definido con una clave, y ese recurso debe aparecer léxicamente antes que la referencia al recurso. Las referencias adelantadas no se pueden resolver mediante una referencia a recurso XAML. Por este motivo, si usas referencias a recursos XAML desde otro recurso, debes diseñar la estructura del diccionario de recursos de manera que en el diccionario de recursos se definan primero aquellos recursos que son utilizados por otros recursos.

Los recursos definidos en el nivel de la aplicación no pueden hacer referencia a recursos inmediatos. Esto equivale a intentar una referencia adelantada, porque los recursos de la aplicación se procesan en primer lugar (cuando la aplicación se inicia por primera vez y antes de que se cargue cualquier contenido de página de navegación). Sin embargo, los recursos inmediatos pueden hacer referencia a un recurso de la aplicación, lo que puede resultar una técnica útil para evitar situaciones de referencias adelantadas.

Ámbito de uso de UserControl

Un elemento UserControl es un caso especial del comportamiento de la búsqueda de recursos porque tiene los conceptos inherentes de ámbito de definición y ámbito de uso. Un UserControl que hace referencia a un recurso XAML desde su ámbito de definición debe poder admitir la búsqueda de dicho recurso en su propia secuencia de búsqueda del ámbito de definición; es decir, no puede acceder a los recursos de la aplicación. Desde el ámbito de uso de un UserControl, la referencia a un recurso se trata como si se realizara desde dentro de la secuencia de búsqueda hacia la raíz de la página de uso (igual que cualquier otra referencia a recursos que se realiza desde un objeto en un árbol de objetos cargados) y puede acceder a los recursos de la aplicación.

ResourceDictionary y XamlReader.Load

Un ResourceDictionary se puede usar como raíz o como parte de la entrada XAML para el método XamlReader.Load. También puedes incluir referencias a recursos XAML en ese código XAML si todas estas referencias están completamente autocontenidas en el código XAML para su carga. XamlReader.Load analiza el código XAML en un contexto que no tiene constancia de otros objetos ResourceDictionary, ni siquiera Application.Resources. Además, no uses {ThemeResource} desde el código XAML enviado a XamlReader.Load.

Uso de ResourceDictionary desde el código

La mayoría de escenarios para un ResourceDictionary se controlan exclusivamente en XAML. Declaras el contenedor ResourceDictionary y los recursos que incluye como un archivo XAML o un conjunto de nodos XAML en un archivo de definición de interfaz de usuario. Y, a continuación, usas referencias a recursos XAML para solicitar esos recursos de otras partes del código XAML. Aun así, hay ciertos casos en que tu aplicación podría querer ajustar el contenido de un ResourceDictionary con código que se ejecute mientras se ejecute la aplicación, o, al menos, consultar el contenido de un ResourceDictionary para ver si ya se definió un recurso. Las llamadas a este código se realizan en una instancia de ResourceDictionary, por lo que primero tienes que recuperar una, bien un ResourceDictionary inmediato en algún lugar del árbol de objetos mediante la obtención de FrameworkElement.Resources, o Application.Current.Resources.

En el código de C# o Microsoft Visual Basic, puedes hacer referencia a un recurso en un ResourceDictionary determinado con el indizador (Item). Un ResourceDictionary es un diccionario de claves de cadena, por lo que el indizador usa la clave de cadena en lugar de un índice de entero. En extensiones de componentes de Visual C++ (C++/CX), usa Lookup.

Cuando usas código para examinar o cambiar un ResourceDictionary, el comportamiento de API, como Lookup o Item, no se desvía de los recursos inmediatos a los recursos de la aplicación, ya que ese es un comportamiento del analizador XAML que solo tiene lugar al cargar las páginas XAML. En tiempo de ejecución, el ámbito de las claves es independiente en la instancia de ResourceDictionary que se usa en ese momento, aunque sí se extiende a MergedDictionaries.

Además, si solicitas una clave que no existe en el ResourceDictionary, puede que no se produzca un error, sino que el valor devuelto sea simplemente null. Pero aún obtendrás un error si intentas usar el null devuelto como valor. El error se originará en el establecedor de la propiedad, no en la llamada de ResourceDictionary. La única forma de evitar el error es si la propiedad acepta null como un valor válido. Este comportamiento contrasta con el comportamiento de búsqueda del XAML en tiempo de análisis del XAML: si no se puede resolver la clave proporcionada desde el XAML en tiempo de análisis, se produce un error de análisis del XAML, incluso aunque la propiedad haya aceptado el valor null.

Los diccionarios de recursos combinados se incluyen en el ámbito de índice del diccionario de recursos principal que hace referencia al diccionario combinado en tiempo de ejecución. En otras palabras, puedes usar los elementos Item o Lookup del diccionario principal para encontrar los objetos que se definieron en el diccionario combinado. En este caso, el comportamiento de la búsqueda se asemeja al comportamiento de la búsqueda de XAML en tiempo de análisis: si hay varios objetos en diccionarios combinados, todos con la misma clave, se devuelve el objeto del último diccionario agregado.

Está permitido agregar elementos a un ResourceDictionary existente mediante una llamada a Add (C# o Visual Basic) o a Insert (C++/CX). Puedes agregarlos a recursos inmediatos o a recursos de la aplicación. Todas estas llamadas a API requieren una clave, lo que satisface el requisito de que cada elemento de un ResourceDictionary tenga una clave. Sin embargo, los elementos que agregues a un ResourceDictionary en tiempo de ejecución no son relevantes para las referencias a recursos XAML. La búsqueda necesaria de referencias a recursos XAML se produce cuando ese XAML se analiza primero según se carga la aplicación (o se detecta un cambio de tema). Los recursos agregados a colecciones en tiempo de ejecución no estaban disponibles entonces, y la alteración del ResourceDictionary no invalida un recurso ya recuperado, incluso si cambias el valor de ese recurso.

También puedes quitar elementos de un ResourceDictionary en tiempo de ejecución, crear copias de algunos o de todos los elementos, y otras operaciones. La lista de miembros de ResourceDictionary indica qué API están disponibles. Ten en cuenta que como ResourceDictionary tiene una API proyectada para admitir las interfaces de la colección subyacentes, las opciones de tu API diferirán según si usas C# o Visual Basic respecto a C++/CX.

ResourceDictionary y localización

Inicialmente, un ResourceDictionary de XAML podría contener cadenas localizables. En este caso, guarda estas cadenas como recursos del proyecto en lugar de en un ResourceDictionary. Extrae las cadenas del código XAML y asigna al elemento propietario un valor x:Uid. A continuación, define un recurso en un archivo de recursos. Proporciona un nombre para el recurso con el formato XUIDValue.PropertyName y un valor con la cadena que debe localizarse. Para obtener más información, consulta Inicio rápido: traducción de recursos de interfaz de usuario.

Optimización de la carga de recursos en Windows 8.1

A partir de Windows 8.1, dispones de una optimización de carga de recursos que está habilitada por el modelo de aplicaciones y el analizador XAML de Windows en tiempo de ejecución. En Windows 8, el analizador XAML cargaba los recursos desde app.xaml y creaba cada uno de ellos como objetos que formaban parte del inicio. Este método no resultaba muy eficaz si contenía diccionarios grandes. Además, los recursos incluían elementos definidos para tres temas, y solo el tema actual era realmente necesario. A partir de Windows 8.1, el analizador XAML solo crea los recursos cuando las referencias de recursos XAML los solicitan expresamente. Estas pueden provenir de otros recursos o del código XAML de página cuando se carga cada página. El comportamiento optimizado del analizador XAML reduce el tiempo necesario para leer el diccionario del nivel de la aplicación en el inicio y permite que la primera página de la aplicación se cargue más rápido en la mayoría de los casos. Los recursos necesarios para los temas inactivos solo se cargan si el usuario activa uno de esos temas. Los usuarios no suelen cambiar de tema mientras se ejecuta la aplicación. Pero, si esto sucede, los recursos en los que se usaba la extensión de marcado ThemeResource para la solicitud se recalculan en función del nuevo tema activo.

Comportamiento de Windows 8

Windows 8 no contaba con las optimizaciones descritas anteriormente. Debido a esto, podías ver algunas diferencias en tiempo al compilar de nuevo la aplicación para Windows 8.1. La aplicación debe cargarse más rápido, pero puede que no sea posible aislar esta mejora frente a otros cambios realizados en el código de la aplicación como parte de la nueva compilación. Algunos de los lugares en que puedes ver pruebas de cambios de tiempo debidos a una carga de recursos mejorada incluyen cuando el analizador llama a los constructores, en el caso de objetos como objetos Application, conversores u otras clases personalizadas. Las aplicaciones compiladas para Windows 8 que se ejecuten en Windows 8.1 siguen usando el comportamiento de Windows 8.

Búsqueda de recursos personalizada

Para los escenarios avanzados, puedes implementar una clase que pueda tener un comportamiento distinto que el comportamiento de búsqueda de referencias a recursos XAML descrito en este tema. Para ello, implementa la clase CustomXamlResourceLoader y, a continuación, podrás acceder a ese comportamiento mediante el uso de la extensión de marcado CustomResource para referencias de recursos en vez de usar StaticResource o ThemeResource. La mayoría de las aplicaciones no tendrán escenarios que requieran esto. Para obtener más información, consulta CustomXamlResourceLoader.

Temas relacionados

ResourceDictionary
Introducción a XAML
Extensión de marcado StaticResource
Extensión de marcado ThemeResource
Referencia a recursos de temas en XAML
Inicio rápido: traducción de recursos de interfaz de usuario
Inicio rápido: dar estilo a los controles
Muestra de recursos de la aplicación y localización
Atributo x:Key

 

 

Mostrar:
© 2017 Microsoft