Información general sobre recursos

En esta introducción se describe el uso de los recursos de WPF como una manera simple de reutilizar los objetos y valores que se definen de forma común. Esta introducción se centra en cómo utilizar los recursos en XAML. También se pueden crear y obtener acceso a los recursos utilizando código o, de forma intercambiable, código y Extensible Application Markup Language (XAML). Para obtener más información, vea Recursos y código.

Este tema contiene las secciones siguientes.

  • Utilizar recursos en XAML
  • Recursos estáticos y recursos dinámicos
  • Estilos, plantillas de datos y claves implícitas
  • Temas relacionados

Utilizar recursos en XAML

En el ejemplo siguiente se define un objeto SolidColorBrush como un recurso en el elemento raíz de una página. A continuación, el ejemplo hace referencia al recurso y lo utiliza para establecer las propiedades de varios elementos secundarios, incluyendo un objeto Ellipse, un objeto TextBlock y un objeto Button.

<Page Name="root"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
  <Page.Resources>
    <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
    <Style TargetType="Border" x:Key="PageBackground">
      <Setter Property="Background" Value="Blue"/>
    </Style>
    <Style TargetType="TextBlock" x:Key="TitleText">
      <Setter Property="Background" Value="Blue"/>
      <Setter Property="DockPanel.Dock" Value="Top"/>
      <Setter Property="FontSize" Value="18"/>
      <Setter Property="Foreground" Value="#4E87D4"/>
      <Setter Property="FontFamily" Value="Trebuchet MS"/>
      <Setter Property="Margin" Value="0,40,10,10"/>
    </Style>
    <Style TargetType="TextBlock" x:Key="Label">
      <Setter Property="DockPanel.Dock" Value="Right"/>
      <Setter Property="FontSize" Value="8"/>
      <Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
      <Setter Property="FontFamily" Value="Arial"/>
      <Setter Property="FontWeight" Value="Bold"/>
      <Setter Property="Margin" Value="0,3,10,0"/>
    </Style>
  </Page.Resources>
  <StackPanel>
    <Border Style="{StaticResource PageBackground}">
      <DockPanel>
        <TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
        <TextBlock Style="{StaticResource Label}">Label</TextBlock>
        <TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left" FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
        <Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
        <Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100" Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
      </DockPanel>
    </Border>
  </StackPanel>
</Page>


Cada elemento del marco de trabajo (FrameworkElement o FrameworkContentElement) tiene una propiedad Resources, que es la que contiene los recursos (como un objeto ResourceDictionary) definidos por un recurso. Los recursos se pueden definir en cualquier elemento. Sin embargo, normalmente se definen en el elemento raíz que, en el ejemplo, es Page.

Cada recurso incluido en un diccionario de recursos debe tener una clave única. Al definir los recursos en el marcado, se asigna la clave única a través de x:Key (Directiva). Normalmente, la clave es una cadena; sin embargo, también se puede establecer en objetos de otros tipos utilizando las extensiones de marcado adecuadas. Las claves de recursos que no son de cadena se utilizan en ciertas áreas de características en WPF, principalmente en los estilos, los recursos de componentes y los estilos de datos.

Una vez definido un recurso, se puede hacer referencia al recurso que se debe utilizar para un valor de propiedad utilizando una sintaxis de extensión de marcado de recursos que especifique el nombre de la clave, como por ejemplo:

<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>

En el ejemplo anterior, cuando el cargador XAML procesa el valor {StaticResource MyBrush} para la propiedad Background de Button, la lógica de búsqueda de recursos comprueba primero la existencia del elemento Button en el diccionario de recursos. Si Button no tiene una definición de la clave de recurso MyBrush (no la tiene; su colección de recursos está vacía), la búsqueda comprueba a continuación el elemento primario de Button, que es Page. Así, cuando se define un recurso en el elemento raíz Page, todos los elementos del árbol lógico del objeto Page pueden tener acceso a él y se puede reutilizar el mismo recurso para establecer el valor de cualquier propiedad que acepte el objeto Type que representa el recurso. En el ejemplo anterior, el mismo recurso MyBrush establece dos propiedades diferentes: la propiedad Background de un objeto Button y la propiedad Fill de un objeto Rectangle.

Recursos estáticos y recursos dinámicos

Se puede hacer referencia a un recurso como un recurso estático o como un recurso dinámico. Para ello, se utiliza Extensión de marcado StaticResource o Extensión de marcado DynamicResource. Una extensión de marcado es una característica de XAML que permite especificar una referencia de objeto y que procesa la cadena del atributo y devuelve el objeto a un cargador XAML. Para obtener más información sobre el comportamiento de la extensión de marcado, vea Extensiones de marcado y XAML de WPF.

Cuando se utiliza una extensión de marcado, normalmente se proporcionan uno o varios parámetros en forma de cadena que son procesados por dicha extensión de marcado, en lugar de evaluarse en el contexto de la propiedad que se está estableciendo. Extensión de marcado StaticResource procesa una clave buscando el valor para dicha clave en todos los diccionarios de recursos disponibles. Esto sucede durante la carga, que es el momento en el que el proceso de carga necesita asignar el valor de la propiedad que acepta la referencia de recurso estático. Extensión de marcado DynamicResource, por el contrario, procesa una clave creando una expresión, y dicha expresión permanece sin evaluar hasta que se ejecuta la aplicación, momento en el cual se evalúa y proporciona un valor.

Al hacer referencia a un recurso, las consideraciones siguientes pueden influir a la hora de decidir si se va a utilizar una referencia de recurso estático o una referencia de recurso dinámico:

  • El diseño general utilizado para crear los recursos para la aplicación (por página, en la aplicación, en XAML separado, en un ensamblado sólo para recursos).

  • La funcionalidad de la aplicación: ¿la actualización de recursos en tiempo real forma parte de los requisitos de la aplicación?

  • El comportamiento de búsqueda respectivo de ese tipo de referencia de recurso.

  • El tipo concreto de recurso o de propiedad, así como el comportamiento nativo de esos tipos.

Recursos estáticos

Las referencias de recursos estáticos funcionan mejor en las circunstancias siguientes:

  • El diseño de la aplicación concentra la mayoría de sus recursos en diccionarios de recursos en el nivel de aplicación o de página. Las referencias de recursos estáticos no se vuelven a evaluar basándose en los comportamientos en tiempo de ejecución, como recargar una página, por lo que puede haber cierta mejora en el rendimiento si se evita el uso de grandes cantidades de referencias de recursos dinámicos cuando no son necesarias para el diseño de los recursos y de la aplicación.

  • Está estableciendo el valor de una propiedad que no está en un objeto DependencyObject o Freezable.

  • Está creando un diccionario de recursos que se compilará en una DLL y que se empaquetará como parte de la aplicación o se compartirá entre distintas aplicaciones.

  • Está creando un tema para un control personalizado y está definiendo recursos que se utilizan dentro de los temas. En este caso, no es conveniente utilizar el comportamiento de búsqueda de referencia de recursos dinámicos, sino el comportamiento de referencia de recursos estáticos con objeto de que la búsqueda sea predecible y se circunscriba al tema. Con una referencia de recursos dinámicos, incluso una referencia dentro de un tema permanecerá sin evaluar hasta el tiempo de ejecución, y existe la posibilidad de que cuando se aplique el tema, algún elemento local redefina una clave a la que el tema está intentando hacer referencia, con lo que dicho elemento se encontrará antes que el propio tema durante la búsqueda. Si este es el caso, el tema no se comportará de la manera esperada.

  • Está utilizando los recursos para establecer un gran número de propiedades de dependencia. Las propiedades de dependencia permiten el almacenamiento en caché del valor efectivo tal y como ha sido habilitado por el sistema de propiedades, por lo que si se proporciona un valor para una propiedad de dependencia que se puede evaluar en el momento de la carga, dicha propiedad no tendrá que comprobar la existencia de una expresión que se ha vuelto a evaluar y podrá devolver el último valor efectivo. Esta técnica puede suponer una mejora en el rendimiento.

  • Desea cambiar el recurso subyacente para todos los consumidores o mantener instancias modificables independientes para cada consumidor utilizando Atributo x:Shared.

Comportamiento de la búsqueda de recursos estáticos

  1. El proceso de búsqueda comprueba la presencia de la clave solicitada dentro del diccionario de recursos definido por el elemento que establece la propiedad.

  2. A continuación, el proceso de búsqueda recorre en sentido ascendente el árbol lógico, hacia el elemento primario y su diccionario de recursos. Este proceso continúa hasta que se alcanza el elemento raíz.

  3. Por último, se comprueban los recursos de la aplicación. Los recursos de la aplicación son los existentes dentro del diccionario de recursos definido por el objeto Application para la aplicación de WPF.

Las referencias de recursos estáticos desde un diccionario de recursos deben hacer referencia a un recurso que haya sido definido léxicamente con anterioridad. Las referencias adelantadas no se pueden resolver mediante una referencia de recurso estático. Por este motivo, si utiliza referencias de recursos estáticos, debe diseñar la estructura de los diccionarios de recursos de tal forma que los recursos pensados para su uso individual se definan en o cerca del principio de los respectivos diccionarios.

La búsqueda de recursos estáticos se puede ampliar a los temas, o a los recursos del sistema, pero esto sólo se admite porque el cargador XAML aplaza la solicitud. Este aplazamiento es necesario para que el tema en tiempo de ejecución en el momento cargar la página se aplique correctamente a la aplicación. Sin embargo, no se recomienda el uso de referencias de recursos estáticos a claves que sólo existen en temas o como recursos del sistema. Esto se debe a que dichas referencias no se vuelven a evaluar si el usuario cambia el tema en tiempo real. Las referencias de recursos dinámicos son más confiables cuando se solicitan recursos del tema o del sistema. La excepción se produce cuando el propio elemento del tema solicita otro recurso. Por las razones mencionadas anteriormente, estas referencias deberían ser referencias de recursos estáticos.

El comportamiento de excepción varía si no se encuentra una referencia de recurso estático. Si se aplazase el recurso, la excepción se produciría en tiempo de ejecución. Si no se aplazase el recurso, la excepción se produciría en el momento de la carga.

Recursos dinámicos

Los recursos dinámicos funcionan mejor en las circunstancias siguientes:

  • El valor del recurso depende de condiciones que no se conocen hasta el tiempo de ejecución. Esto incluye los recursos del sistema, o los recursos que de otra forma serían establecidos por el usuario. Por ejemplo, puede crear valores de establecedor que hacen referencia a las propiedades del sistema, de la forma expuesta por SystemColors, SystemFonts o SystemParameters. Estos valores son auténticamente dinámicos porque proceden del entorno en tiempo de ejecución del usuario y del sistema operativo. También es posible tener temas de nivel de aplicación que pueden cambiar, en los que el acceso a recursos de nivel de página también debe capturar los cambios.

  • Está creando o haciendo referencia a los estilos del tema para un control personalizado.

  • Desea ajustar el contenido de un objeto ResourceDictionary durante la duración de una aplicación.

  • Dispone de una estructura de recursos compleja que tiene interdependencias, y en la que es posible que se necesite una referencia adelantada. A diferencia de las referencias de recursos estáticos, las referencias de recursos dinámicos admiten las referencias adelantadas, ya que no es necesario evaluar el recurso hasta el tiempo de ejecución y, por consiguiente, las referencias adelantadas no son un concepto pertinente.

  • Está haciendo referencia a un recurso que es de gran tamaño desde la perspectiva de un espacio de compilación o de trabajo, y es posible que dicho recurso no se utilice inmediatamente al cargar la página. Las referencias de recursos estáticos siempre se cargan desde XAML al cargar la página; sin embargo, una referencia de un recurso dinámico no lo hace hasta que se utiliza realmente.

  • Está creando un estilo cuyos valores de establecedor podrían proceder de otros valores influenciados por los temas o por otras configuraciones del usuario.

  • Está aplicando recursos a elementos que podrían haber cambiado de elemento primario en el árbol lógico durante la duración de la aplicación. Al cambiar el elemento primario, también se cambia potencialmente el ámbito de búsqueda de recursos, por lo que si desea que el recurso para un elemento que ha cambiado de elemento primario se vuelva a evaluar dependiendo del nuevo ámbito, siempre debe utilizar una referencia de recurso dinámico.

Comportamiento de la búsqueda de recursos dinámicos

El comportamiento de búsqueda de recursos para una referencia de recurso dinámico es similar al comportamiento de búsqueda establecido en el código si se llama a FindResource o a SetResourceReference.

  1. El proceso de búsqueda comprueba la presencia de la clave solicitada dentro del diccionario de recursos definido por el elemento que establece la propiedad.

  2. A continuación, el proceso de búsqueda recorre en sentido ascendente el árbol lógico, hacia el elemento primario y su diccionario de recursos. Este proceso continúa hasta que se alcanza el elemento raíz.

  3. Por último, se comprueban los recursos de la aplicación. Los recursos de la aplicación son los existentes dentro del diccionario de recursos definido por el objeto Application para la aplicación de WPF.

  4. Se comprueba la existencia del tema activo actualmente en el diccionario de recursos de temas. Si el tema cambia en tiempo de ejecución, se vuelve a evaluar el valor.

  5. Se comprueban los recursos del sistema.

El comportamiento de excepción (si existe) varía:

  • Si una llamada a FindResource solicita un recurso, y éste no se encuentra, se inicia una excepción.

  • Si una llamada a TryFindResource solicita un recurso, y éste no se encuentra, no se inicia ninguna excepción, pero el valor devuelto es null. Si la propiedad que se establece no acepta null, todavía es posible que se inicie un excepción más profunda (esto depende de la propiedad individual que se esté estableciendo).

  • Si una referencia de recurso dinámico solicitara un recurso en XAML, y éste no se encontrara, el comportamiento dependerá del sistema general de propiedades, pero el comportamiento general es como si no se hubiera producido ninguna operación de configuración de propiedades en el nivel en el que existe el recurso. Por ejemplo, si intenta establecer el fondo de un elemento de botón individual utilizando un recurso que no se ha podido evaluar, no se devuelve ningún conjunto de valores, pero el valor efectivo todavía puede proceder de otros participantes en el sistema de propiedades y en la prioridad de valores. Por ejemplo, el valor del fondo todavía podría proceder de un estilo de botón definido localmente o del estilo del tema. Para las propiedades que no se definen en los estilos de tema, el valor efectivo después de una evaluación de recursos con errores podría proceder del valor predeterminado en los metadatos de la propiedad.

Restricciones

Las referencias de recursos dinámicos tienen algunas restricciones importantes. Al menos debe cumplirse una de las condiciones siguientes:

Dado que la propiedad que se establece debe ser una propiedad de DependencyProperty o Freezable, la mayoría de los cambios en la propiedad se pueden propagar a la interfaz de usuario debido a que dichos cambios (el valor de recurso dinámico modificado) están confirmados por el sistema de propiedades. La mayoría de los controles incluyen lógica que forzará otro diseño del control si cambia un objeto DependencyProperty y esa propiedad podría afectar al diseño. Sin embargo, no está garantizado que todas las propiedades que tengan una Extensión de marcado DynamicResource como valor proporcionen éste de manera que se actualicen en tiempo real en la interfaz de usuario. Esa funcionalidad podría variar dependiendo de la propiedad, así como del tipo que posea ésta o incluso de la estructura lógica de la aplicación.

Estilos, plantillas de datos y claves implícitas

Anteriormente, se ha dicho que todos los elementos de un objeto ResourceDictionary deben tener una clave. Sin embargo, eso no significa que todos los recursos deben tener un atributo x:Key explícito. Varios tipos de objetos admiten una clave implícita cuando se definen como un recurso, donde el valor de la clave está asociado al valor de otra propiedad. Esto se conoce como una clave implícita, mientras que un atributo x:Key es una clave explícita. Se puede sobrescribir cualquier clave implícita especificando una clave explícita.

Un escenario muy importante para los recursos es el obtenido al definir un objeto Style. De hecho, Style se define casi siempre como una entrada en un diccionario de recursos, ya que los estilos están pensados intrínsecamente para su reutilización. Para obtener más información acerca de los estilos, vea Aplicar estilos y plantillas.

Los estilos para los controles se pueden crear con una clave implícita; así mismo, también se puede hacer referencia a ellos mediante dicha clave. Los estilos del tema que definen la apariencia predeterminada de un control se basan en esta clave implícita. La clave implícita desde el punto de vista de la solicitud es el objeto Type del propio control. La clave implícita desde el punto de vista de la definición del recurso es la propiedad TargetType del estilo. Por consiguiente, si está creando temas para controles personalizados, al crear estilos que interactúan con estilos de tema existentes no necesita especificar un x:Key (Directiva) para ese objeto Style. Y si desea utilizar los estilos con tema, no es necesario que especifique ningún estilo. Por ejemplo, la definición de estilo siguiente funciona, aunque el recurso Style no parece tener una clave:

<Style TargetType="Button">
  <Setter Property="Background">
    <Setter.Value>
      <LinearGradientBrush>
        <GradientStop Offset="0.0" Color="AliceBlue"/>
        <GradientStop Offset="1.0" Color="Salmon"/>           
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>  
  <Setter Property="FontSize" Value="18"/>
</Style>

En realidad, el estilo tiene una clave: la clave implícita typeof(Button). En el marcado, puede especificar directamente una propiedad TargetType como nombre del tipo (o también puede utilizar {x:Type...} para devolver un objeto Type.

A través de los mecanismos de estilo del tema predeterminado utilizados por WPF, ese estilo se aplica como el estilo en tiempo de ejecución de un objeto Button en la página, aunque el propio objeto Button no intenta especificar su propiedad Style o una referencia de recurso concreta al estilo. El estilo definido en la página se encontrará antes que el estilo de diccionario de tema en la secuencia de búsqueda, utilizando la misma clave que este último estilo. También podría especificar <Button>Hello</Button> en cualquier lugar de la página, y el estilo definido con la propiedad TargetType de Button se aplicaría a ese botón. Si lo desea, también puede asignar explícitamente al estilo el mismo valor de tipo que TargetType, por motivos de claridad en el marcado, pero eso es opcional.

Las claves implícitas para los estilos no se aplican en un control si OverridesDefaultStyle es true (observe también que OverridesDefaultStyle se podría establecer como parte del comportamiento nativo para la clase de control, en lugar de establecerse explícitamente en una instancia del control). Asimismo, para poder admitir las claves implícitas para los escenarios de clase derivada, el control debe invalidar DefaultStyleKey (todos los controles existentes proporcionados como parte de WPF hacen esto). Para obtener más información sobre el diseño de estilos, temas y controles, vea Instrucciones para el diseño de controles con estilos.

DataTemplate también tiene una clave implícita. La clave implícita para un objeto DataTemplate es el valor de la propiedad DataType. DataType también se puede especificar como el nombre del tipo en lugar de hacerlo explícitamente utilizando {x:Type...}. Para obtener información detallada, vea Información general sobre plantillas de datos.

Vea también

Tareas

Cómo: Definir y hacer referencia a un recurso

Referencia

x:Type (Extensión de marcado)

ResourceDictionary

Extensión de marcado StaticResource

Extensión de marcado DynamicResource

Conceptos

Optimizar el rendimiento: Recursos de aplicación

Recursos y código

Información general sobre la administración de aplicaciones