Información general sobre las propiedades de dependencia

Windows Presentation Foundation (WPF) proporciona un conjunto de servicios que se pueden utilizar para extender la funcionalidad de una propiedad de common language runtime (CLR). Colectivamente, estos servicios se conocen como el sistema de propiedades de WPF. Una propiedad que está respaldada por el sistema de propiedades de WPF se conoce como propiedad de dependencia. En esta introducción se describe el sistema de propiedades de WPF y las funciones de una propiedad de dependencia. Esto incluye cómo utilizar propiedades de dependencia existentes en XAML y en el código. Esta información general también presenta aspectos especializados de las propiedades de dependencia, tales como los metadatos de propiedades de dependencia y cómo crear una propiedad de dependencia propia en una clase personalizada.

Este tema contiene las secciones siguientes.

  • Requisitos previos
  • Propiedades de dependencia y propiedades de CLR
  • Propiedades CLR de respaldo de propiedades de dependencia
  • Establecer valores de propiedad
  • Funcionalidad de propiedad proporcionada por una propiedad de dependencia
  • Prioridad de los valores de propiedades de dependencia
  • Más información sobre propiedades de dependencia
  • Temas relacionados

Requisitos previos

En este tema se asume que tiene conocimientos básicos sobre CLR y sobre programación orientada a objetos. Para seguir los ejemplos de este tema, también debe entender XAML y debe saber escribir aplicaciones de WPF. Para obtener más información, consulte Tutorial: Introducción a WPF.

Propiedades de dependencia y propiedades de CLR

En WPF, las propiedades se exponen normalmente como propiedades common language runtime (CLR). En un nivel básico, podría interactuar directamente con estas propiedades y nunca sabría que se implementan como una propiedad de dependencia. Sin embargo, es recomendable conocer algunas o todas las características del sistema de propiedades de WPF, para poder aprovechar estas características.

El propósito de las propiedades de dependencia es proporcionar una manera de calcular el valor de una propiedad en función del valor de otras entradas. Estas otras entradas pueden incluir propiedades del sistema tales como temas y preferencias del usuario, mecanismos de determinación de propiedad Just-In-Time tales como el enlace de datos y las animaciones o guiones gráficos, plantillas del uso múltiple tales como recursos y estilos, o valores conocidos a través de relaciones de elementos primarios-secundarios con otros elementos del árbol de elementos. Además, una propiedad de dependencia se puede implementar para que proporcione validación autónoma, valores predeterminados, devoluciones de llamada que supervisen los cambios de otras propiedades y un sistema que pueda forzar valores de la propiedad en función de información que puede estar disponible en tiempo de ejecución. Las clases derivadas también pueden cambiar algunas características concretas de una propiedad existente invalidando metadatos de propiedades de dependencia, en lugar de reemplazar la implementación real de propiedades existentes o crear propiedades nuevas.

En la referencia de SDK, puede identificar qué propiedad es una propiedad de dependencia por la presencia de la sección de Información de propiedad de dependencia en la página de referencia administrada para esa propiedad. La sección de Información de propiedad de dependencia incluye un vínculo al campo identificador de DependencyProperty para esa propiedad de dependencia y también incluye una lista de las opciones de metadatos establecidas para esa propiedad, información de invalidación por clases y otros detalles.

Propiedades CLR de respaldo de propiedades de dependencia

Las propiedades de dependencia y el sistema de propiedades de WPF extienden la funcionalidad de propiedad proporcionando un tipo que respalda una propiedad, como implementación alternativa al modelo estándar de respaldar la propiedad con un campo privado. El nombre de este tipo es DependencyProperty. El otro tipo importante que define el sistema de propiedades de WPF es DependencyObject.DependencyObject define la clase base que puede registrar y poseer una propiedad de dependencia.

A continuación se ofrece un resumen de la terminología que se utiliza en esta documentación de software development kit (SDK) cuando se tratan las propiedades de dependencia:

  • Propiedad de dependencia: una propiedad respaldada por un objeto DependencyProperty.

  • Identificador de propiedad de dependencia: una instancia de DependencyProperty, que se obtiene como valor de retorno al registrar una propiedad de dependencia y, a continuación, se almacena como miembro estático de una clase. Este identificador se utiliza como parámetro para muchas de las APIs que interactúan con el sistema de propiedades de WPF.

  • ""Contenedor" CLR: implementaciones reales de lectura y escritura de la propiedad. Estas implementaciones incorporan el identificador de propiedad de dependencia utilizándolo en las llamadas a GetValue y SetValue, proporcionando así el respaldo para la propiedad utilizando el sistema de propiedades de WPF.

En el ejemplo siguiente se muestra la propiedad propiedad de dependencia IsSpinning y se muestra la relación del identificador DependencyProperty con la propiedad a la que respalda.

Public Shared ReadOnly IsSpinningProperty As DependencyProperty =
    DependencyProperty.Register("IsSpinning",
                                GetType(Boolean),
                                GetType(MyCode))

Public Property IsSpinning() As Boolean
    Get
        Return CBool(GetValue(IsSpinningProperty))
    End Get
    Set(ByVal value As Boolean)
        SetValue(IsSpinningProperty, value)
    End Set
End Property
public static readonly DependencyProperty IsSpinningProperty = 
    DependencyProperty.Register(
    "IsSpinning", typeof(Boolean),


...


    );
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}

La convención de nomenclatura de la propiedad y su campo de respaldo DependencyProperty es importante. El nombre del campo siempre es el nombre de la propiedad, con el sufijo Property. Para obtener más información sobre esta convención y sus razones, vea Propiedades de dependencia personalizadas.

Establecer valores de propiedad

Puede establecer propiedades en código o en XAML.

Establecer valores de propiedad en XAML

En el siguiente ejemplo de XAML se especifica el rojo como color de fondo de un botón. En este ejemplo se muestra un caso donde el analizador de XAML de WPF convierte el tipo de un valor de cadena simple de un atributo XAML en un tipo WPF (Color, mediante SolidColorBrush) en el código generado.

<Button Background="Red" Content="Button!"/>

XAML admite diversas formas de sintaxis para establecer propiedades. La sintaxis a utilizar para una propiedad determinada dependerá del tipo de valor que utilice una propiedad, así como de otros factores tales como la presencia de un convertidor de tipos. Para obtener más información sobre la sintaxis XAML para establecer propiedades, vea Información general sobre XAML (WPF) y Detalles de la sintaxis XAML.

Como ejemplo de sintaxis sin atributos, en el siguiente ejemplo de XAML se muestra otro fondo de botón. Esta vez, en lugar de establecer un color sólido simple, el fondo se establece en una imagen, con un elemento que representa esa imagen y el origen de la imagen especificado como un atributo del elemento anidado. Éste es un ejemplo de sintaxis de elemento de propiedad.

<Button Content="Button!">
  <Button.Background>
    <ImageBrush ImageSource="wavy.jpg"/>
  </Button.Background>
</Button>

Establecer propiedades en código

Establecer valores de propiedad de dependencia en código suele consistir en una simple llamada a la implementación de escritura expuesta por el "contenedor" de CLR. 

        Dim myButton As New Button()
        myButton.Width = 200.0
Button myButton = new Button();
myButton.Width = 200.0;

Obtener un valor de propiedad consiste también esencialmente en una llamada a la implementación de lectura del "contenedor":

        Dim whatWidth As Double
        whatWidth = myButton.Width
double whatWidth;
whatWidth = myButton.Width;

También puede llamar directamente a APIsGetValue y SetValue del sistema de propiedades. Habitualmente, no es necesario si se está utilizando propiedades existentes (los contenedores son más cómodos y ofrecen una mejor exposición de la propiedad para las herramientas de desarrollo), pero llamar directamente a APIs es lo adecuado para ciertos escenarios.

También se pueden establecer propiedades en XAML y obtener acceso más tarde en el código mediante código subyacente. Para obtener información detallada, vea Código subyacente y XAML en WPF.

Funcionalidad de propiedad proporcionada por una propiedad de dependencia

Una propiedad de dependencia proporciona funcionalidad que extiende la funcionalidad de una propiedad, a diferencia de una propiedad respaldada por un campo. A menudo, cada una de estas funcionalidades representa o admite una característica concreta del conjunto total de propiedades de WPF:

  • Recursos

  • Enlace de datos

  • Estilos

  • Animations

  • Invalidaciones de metadatos

  • Herencia del valor de la propiedad

  • Integración de WPF Designer

Recursos

Puede establecerse un valor de propiedad de dependencia haciendo referencia a un recurso. Los recursos se especifican normalmente como el valor de propiedad Resources de un elemento raíz de la página o de la aplicación (estas ubicaciones permiten el acceso más cómodo al recurso). En el ejemplo siguiente se muestra cómo definir un recurso SolidColorBrush.

<DockPanel.Resources>
  <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</DockPanel.Resources>

Una vez definido el recurso, puede hacer referencia al recurso y utilizarlo para proporcionar un valor de propiedad:

<Button Background="{DynamicResource MyBrush}" Content="I am gold" />

Este recurso en especial se conoce como Extensión de marcado DynamicResource (en XAML de WPF, se puede utilizar una referencia de recurso estática o dinámica). Para utilizar una referencia de recurso dinámica debe estar estableciendo una propiedad de dependencia, por lo que es específicamente el uso de la referencia de recurso dinámica lo que habilita el sistema de propiedades de WPF. Para obtener más información, consulte Información general sobre recursos.

NotaNota

Los recursos se tratan como un valor local, lo que significa que si se establece otro valor local, se eliminará la referencia de recurso.Para obtener más información, vea Prioridad de los valores de propiedades de dependencia.

Enlace de datos

Una propiedad de dependencia puede hacer referencia a un valor mediante enlace de datos. El enlace de datos funciona mediante una sintaxis de extensión de marcado concreta en XAML, o el objeto Binding en el código. Con el enlace de datos, la determinación final del valor de la propiedad se aplaza hasta el tiempo de ejecución, momento en el que se obtiene el valor desde un origen de datos.

En el ejemplo siguiente se establece la propiedad Content de un control Button, utilizando un enlace declarado en XAML. El enlace usa un contexto de datos heredado y un origen de datos XmlDataProvider (que no se muestra). El propio enlace especifica la propiedad de origen deseada por XPath dentro del origen de datos.

<Button Content="{Binding XPath=Team/@TeamName}"/>
NotaNota

Los enlaces se tratan como un valor local, lo que significa que, si establece otro valor local, eliminará el enlace.Para obtener información detallada, vea Prioridad de los valores de propiedades de dependencia.

Las propiedades de dependencia o la clase DependencyObject no admiten de forma nativa INotifyPropertyChanged para generar notificaciones de cambios de valor de la propiedad de origen DependencyObject en operaciones de enlace de datos. Para obtener más información sobre cómo crear propiedades para su uso en enlace de datos que puedan informar de los cambios de un destino de enlace de datos, vea Información general sobre el enlace de datos.

Estilos

Los estilos y las plantillas son dos de los principales escenarios que invitan a usar propiedades de dependencia. Los estilos son particularmente útiles para establecer propiedades que definen la user interface (UI) de la aplicación. Los estilos se definen habitualmente como recursos en XAML. Los estilos interactúan con el sistema de propiedades porque contienen normalmente "establecedores" para determinadas propiedades, así como "desencadenadores" que modifican un valor de propiedad en función del valor en tiempo real de otra propiedad.

En el ejemplo siguiente se crea un estilo muy simple (que se definiría dentro de un diccionario Resources, que no se muestra) y, a continuación, se aplica directamente a la propiedad Style de un control Button. El establecedor que hay dentro del estilo establece la propiedad Background de un control Button con estilo en el color verde.

<Style x:Key="GreenButtonStyle">
  <Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>

Para obtener más información, consulte Aplicar estilos y plantillas.

Animations

Las propiedades de dependencia se pueden animar. Cuando se aplica una animación y se está ejecutando, el valor animado funciona en una prioridad más alta que cualquier valor (tal como un valor local) que pueda tener la propiedad.

En el ejemplo siguiente se anima la propiedad Background de una propiedad Button (técnicamente, la propiedad Background se anima utilizando la sintaxis de elemento de propiedad para especificar un objeto SolidColorBrush en blanco como Background; entonces, la propiedad Color de ese objeto SolidColorBrush es la propiedad que se anima directamente).

<Button>I am animated
  <Button.Background>
    <SolidColorBrush x:Name="AnimBrush"/>
  </Button.Background>
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <ColorAnimation
            Storyboard.TargetName="AnimBrush" 
            Storyboard.TargetProperty="(SolidColorBrush.Color)"
            From="Red" To="Green" Duration="0:0:5" 
            AutoReverse="True" RepeatBehavior="Forever" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

Para obtener más información sobre la animación de propiedades, vea Información general sobre animaciones y Información general sobre objetos Storyboard.

Invalidaciones de metadatos

Puede cambiar ciertos comportamientos de una propiedad de dependencia invalidando los metadatos para esa propiedad al derivar de la clase que registra originalmente la propiedad de dependencia. La invalidación de metadatos se apoya en el identificador DependencyProperty. La invalidación de metadatos, no requiere implementar de nuevo la propiedad. El sistema de propiedades administra nativamente el cambio de metadatos; cada clase puede contener metadatos individuales para todas las propiedades heredadas de las clases base, tipo por tipo.

En el ejemplo siguiente se invalidan los metadatos de una propiedad de dependencia DefaultStyleKey. Invalidar los metadatos de esta propiedad de dependencia concreta forma parte de un modelo de implementación que crea controles que pueden utilizar estilos predeterminados de temas.

  Public Class SpinnerControl
      Inherits ItemsControl
      Shared Sub New()
          DefaultStyleKeyProperty.OverrideMetadata(GetType(SpinnerControl), New FrameworkPropertyMetadata(GetType(SpinnerControl)))
      End Sub
  End Class
public class SpinnerControl : ItemsControl
{
    static SpinnerControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(SpinnerControl), 
            new FrameworkPropertyMetadata(typeof(SpinnerControl))
        );
    }
}

Para obtener más información sobre cómo invalidar u obtener metadatos de propiedades, vea Metadatos de las propiedades de dependencia.

Herencia de valores de propiedad

Un elemento puede heredar el valor de una propiedad de dependencia de su elemento primario en el árbol de objetos.

NotaNota

El comportamiento de herencia del valor de la propiedad no está habilitado globalmente para todas las propiedades de dependencia, porque el tiempo de cálculo para la herencia tiene cierto impacto sobre el rendimiento.La herencia del valor de la propiedad solamente está habilitada, normalmente, para las propiedades donde un escenario determinado sugiera que resulta adecuada la herencia del valor de la propiedad.Puede determinar si una propiedad de dependencia se hereda examinando la sección Información de propiedad de dependencia de esa propiedad de dependencia en la referencia del SDK.

En el ejemplo siguiente se muestra un enlace y se establece la propiedad DataContext que especifica el origen del enlace, lo que no se mostraba en el ejemplo de enlace anterior. Los enlaces subsiguientes en objetos secundarios no necesitan especificar el origen, pueden utilizar el valor heredado de DataContext en el objeto StackPanel primario. (Como alternativa, un objeto secundario podría decidir especificar su propio DataContext o Source directamente en Binding y, deliberadamente, no utilizar el valor heredado para el contexto de datos de sus enlaces.)

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource XmlTeamsSource}}">
  <Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>

Para obtener más información, vea Herencia de valores de propiedad.

Integración de WPF Designer

Un control personalizado con propiedades implementadas como propiedades de dependencia recibirá la compatibilidad con WPF Designer for Visual Studio adecuada. Un ejemplo es la capacidad de modificar propiedades de dependencia directas y adjuntas con la ventana Propiedades. Para obtener más información, consulte Información general sobre la creación de controles.

Prioridad de los valores de propiedades de dependencia

Al obtener el valor de una propiedad de dependencia, se está obteniendo potencialmente un valor que se estableció en esa propiedad mediante cualquiera de las demás entradas basadas en propiedad que participan en el sistema de propiedades de WPF. La prioridad de valor de propiedad de dependencia existe para que diversos escenarios de obtención de valores para propiedades puedan interactuar de una manera predecible.

Considere el ejemplo siguiente. El ejemplo incluye un estilo que se aplica a todos los botones y sus propiedades Background, pero también especifica un botón con un valor Background establecido localmente.

NotaNota

La documentación de SDK utiliza ocasionalmente los términos "valor local" o valor "localmente establecido" para explicar las propiedades de dependencia.Un valor localmente establecido es un valor de propiedad que se establece directamente en una instancia de objeto en código o como un atributo de un elemento en XAML.

En principio, para el primer botón, la propiedad se establece dos veces, pero solamente se aplica un valor: el de mayor prioridad. Un valor localmente establecido tiene la prioridad superior (excepto para una animación en ejecución, pero no hay ninguna animación en este ejemplo) y, así, se utiliza el valor establecido localmente en lugar del valor del establecedor del estilo para el segundo plano del primer botón. El segundo botón no tiene ningún valor local (y ningún otro valor con prioridad más alta que un establecedor de estilo) y, así, el fondo de ese botón procede del establecedor del estilo.

<StackPanel>
  <StackPanel.Resources>
    <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
     <Setter Property="Background" Value="Red"/>
    </Style>
  </StackPanel.Resources>
  <Button Background="Green">I am NOT red!</Button>
  <Button>I am styled red</Button>
</StackPanel>

¿Por qué existe la prioridad de propiedad de dependencia?

Normalmente, no se desea que los estilos se apliquen siempre y oculten incluso un valor localmente establecido de un elemento individual (de lo contrario, sería muy difícil utilizar estilos o elementos en general). Por consiguiente, los valores que proceden de estilos funcionan con una prioridad más baja que un valor establecido localmente. Para ver una lista más completa de propiedades de dependencia y de dónde puede proceder el valor efectivo de una propiedad de dependencia, vea Prioridad de los valores de propiedades de dependencia.

NotaNota

Hay varias propiedades definidas en elementos de WPF que no son propiedades de dependencia.Habitualmente, las propiedades se implementan como propiedades de dependencia solamente cuando es necesario admitir por lo menos uno de los escenarios habilitados por el sistema de propiedades: enlace de datos, estilos, animación, compatibilidad con valor predeterminado, herencia, propiedades adjuntas o invalidación.

Más información sobre propiedades de dependencia

  • Una propiedad adjunta es un tipo de propiedad que admite una sintaxis especializada en XAML. Una propiedad adjunta no suele tener una correspondencia 1:1 con una propiedad de common language runtime (CLR) y no es necesariamente una propiedad de dependencia. El propósito típico de una propiedad adjunta es permitir que los elementos secundarios informen de los valores de la propiedad a un elemento primario, aunque el elemento primario y los elementos secundarios no posean esa propiedad como parte de las listas de miembros de la clase. Un escenario primario consiste en permitir que los elementos secundarios informen el elemento primario de cómo se deben presentar en UI; para ver un ejemplo, vea Dock o Left. Para obtener información detallada, vea Información general sobre propiedades asociadas.

  • Los programadores de componentes y los desarrolladores de aplicaciones pueden desear crear propiedades de dependencia propias para habilitar funciones tales como el enlace de datos o la compatibilidad con estilos, o para la invalidación y la coerción de valor. Para obtener información detallada, vea Propiedades de dependencia personalizadas.

  • Generalmente las propiedades de dependencia deben considerarse propiedades públicas, accesibles o, por lo menos, reconocibles por cualquier llamador que tenga acceso a una instancia. Para obtener más información, consulte Seguridad de las propiedades de dependencia.

Vea también

Conceptos

Propiedades de dependencia personalizadas

Propiedades de dependencia de sólo lectura

Información general sobre XAML (WPF)

Arquitectura de WPF