Metadatos de las propiedades de dependencia

El sistema de propiedades de Windows Presentation Foundation (WPF) incluye un sistema de informe de metadatos que va más allá de lo que puede notificarse sobre una propiedad mediante reflexión o las características generales de Common Language Runtime (CLR). Los metadatos de una propiedad de dependencia también los puede asignar de manera exclusiva la clase que define una propiedad de dependencia, se pueden cambiar cuando la propiedad de dependencia se agrega a una clase diferente y los pueden invalidar específicamente todas las clases derivadas que heredan la propiedad de dependencia de la clase base de definición.

Requisitos previos

En este tema se da por hecho que conoce las propiedades de dependencia desde la perspectiva de un consumidor de propiedades de dependencia existentes en las clases de WPF y, asimismo, que ha leído la Información general sobre las propiedades de dependencia. Para seguir los ejemplos de este tema, también debe comprender el lenguaje XAML y saber cómo escribir aplicaciones de WPF.

Uso de los metadatos de las propiedades de dependencia

Los metadatos de las propiedades de dependencia existen como un objeto que se puede consultar para examinar las características de una propiedad de dependencia. El sistema de propiedades también accede con frecuencia a estos metadatos mientras procesa cualquier propiedad de dependencia determinada. El objeto de metadatos de una propiedad de dependencia puede contener los siguientes tipos de información:

  • Valor predeterminado de la propiedad de dependencia, si no se puede determinar ningún otro valor de la propiedad de dependencia según su valor local, estilo, herencia, etc. Para obtener una explicación exhaustiva de cómo participan los valores predeterminados en la precedencia usada por el sistema de propiedades al asignar valores de las propiedades de dependencia, vea Precedencia de valores de propiedad de dependencia.

  • Referencias a las implementaciones de devoluciones de llamada que afectan a los comportamientos de coerción o notificación de cambios por tipo de propietario. Tenga en cuenta que estas devoluciones de llamada se definen a menudo con un nivel de acceso no público, de modo que obtener las referencias reales de los metadatos no suele ser posible a menos que estén dentro de su ámbito de acceso permitido. Para obtener más información sobre las devoluciones de llamada de propiedades de dependencia, consulte Devoluciones de llamada y validación de las propiedades de dependencia.

  • Si la propiedad de dependencia en cuestión se considera una propiedad del nivel de marco de WPF, los metadatos podrían contener características de propiedades de dependencia del nivel de marco de WPF, que comunican los datos y el estado de los servicios, tales como la lógica de herencia de propiedades y el motor de diseño del nivel de marco de WPF. Para obtener más información sobre este aspecto de los metadatos de propiedades de dependencia, consulte Metadatos de las propiedades de marco de trabajo.

API de metadatos

El tipo que notifica la mayor parte de la información de metadatos que se usa en el sistema de propiedades es la clase PropertyMetadata. Las instancias de metadatos se especifican de manera opcional cuando las propiedades de dependencia se registran con el sistema de propiedades y pueden especificarse de nuevo para tipos adicionales que se agreguen a sí mismos como propietarios o invaliden los metadatos que heredan de la definición de propiedad de dependencia de clase base. (En los casos en los que un registro de propiedad no especifique metadatos, se crea un objeto PropertyMetadata predeterminado con valores predeterminados para esa clase). Los metadatos registrados se devuelven como PropertyMetadata al llamar a las diversas sobrecargas de GetMetadata que obtienen metadatos de una propiedad de dependencia en una instancia de DependencyObject.

A continuación, se deriva desde la clase PropertyMetadata para proporcionar metadatos más específicos de divisiones arquitectónicas, tales como las clases del nivel de marco de WPF. UIPropertyMetadata agrega informes de animación, mientras que FrameworkPropertyMetadata proporciona las propiedades del nivel de marco de WPF mencionadas en la sección anterior. El registro de propiedades de dependencia se puede realizar con estas clases derivadas de PropertyMetadata. Cuando se examinan los metadatos, el tipo base PropertyMetadata puede convertirse a las clases derivadas para que pueda examinar las propiedades más específicas.

Nota:

Las características de la propiedad que se pueden especificar en FrameworkPropertyMetadata se denominan ocasionalmente en esta documentación como "marcas". Cuando se crean instancias de metadatos para su uso en registros de propiedades de dependencia o invalidaciones de metadatos, estos valores se especifican mediante la enumeración basada en marcas FrameworkPropertyMetadataOptions y, luego, se proporcionan valores posiblemente concatenados de la enumeración al constructor FrameworkPropertyMetadata. Sin embargo, una vez construidas, estas características de opción se exponen dentro de un objeto FrameworkPropertyMetadata como una serie de propiedades booleanas, en lugar del valor de enumeración de construcción. Las propiedades booleanas permiten comprobar cada condicional, en lugar de exigir que aplique una máscara a un valor de enumeración basada en marcas para obtener la información que le interesa. El constructor usa el elemento concatenado FrameworkPropertyMetadataOptions para mantener una longitud razonable de la signatura del constructor, mientras que los metadatos construidos reales exponen las propiedades discretas para que las consultas de metadatos sean más intuitivas.

Cuándo invalidar metadatos y cuándo derivar una clase

El sistema de propiedades de WPF tiene funcionalidades establecidas para modificar algunas características de las propiedades de dependencia sin necesidad de volver a implementarlas completamente. Esto se logra construyendo una instancia diferente de los metadatos de la propiedad de dependencia tal como existe en un tipo determinado. Tenga en cuenta que la mayoría de las propiedades de dependencia existentes no son propiedades virtuales, de modo que, en el sentido estricto, su "reimplementación" en clases heredadas solo se puede lograr mediante el sombreado del miembro existente.

Si el escenario que intenta habilitar para una propiedad de dependencia en un tipo no se puede lograr con la modificación de las características de las propiedades de dependencia existentes, podría ser necesario crear una clase derivada y, después, declarar una propiedad de dependencia personalizada en su clase derivada. Una propiedad de dependencia personalizada se comporta igual que las propiedades de dependencia que definen las API de WPF. Para obtener más información acerca de las propiedades de dependencia personalizadas, consulte Propiedades de dependencia personalizadas.

Una característica importante de una propiedad de dependencia que no se puede invalidar es su tipo de valor. Si hereda una propiedad de dependencia que tiene el comportamiento aproximado que necesita, pero necesita que tenga un tipo diferente, tendrá que implementar una propiedad de dependencia personalizada y, posiblemente, vincular las propiedades mediante la conversión de tipos u otra implementación en la clase personalizada. Además, no puede reemplazar un objeto ValidateValueCallback existente, porque esta devolución de llamada existe en el propio campo de registro, y no en sus metadatos.

Escenarios para modificar los metadatos existentes

Si está trabajando con los metadatos de una propiedad de dependencia existente, un escenario común para cambiar dichos metadatos es cambiar el valor predeterminado. Cambiar o agregar devoluciones de llamada del sistema de propiedades es un escenario más avanzado. Es posible que quiera hacerlo si su implementación de una clase derivada tiene diferentes interrelaciones entre las propiedades de dependencia. Uno de los condicionales de tener un modelo de programación que admita tanto el uso declarativo como de código es que las propiedades deben poder establecerse en cualquier orden. Por lo tanto, las propiedades dependientes deben establecerse Just-in-Time sin contexto y no pueden depender de saber un orden de configuración como podría darse en un constructor. Para obtener más información sobre este aspecto del sistema de propiedades, consulte Devoluciones de llamada y validación de las propiedades de dependencia. Tenga en cuenta que las devoluciones de llamada de validación no forman parte de los metadatos, sino del identificador de la propiedad de dependencia. Por lo tanto, las devoluciones de llamada de validación no se pueden cambiar mediante la invalidación de los metadatos.

Es posible que en algunos casos también quiera modificar las opciones de metadatos de la propiedad del nivel de marco de WPF en las propiedades de dependencia existente. Estas opciones comunican determinados condicionales conocidos acerca de las propiedades del nivel de marco de WPF a otros procesos del nivel de marco de WPF, como el sistema de diseño. Por lo general, la definición de las opciones se realiza solo al registrar una nueva propiedad de dependencia, pero también es posible cambiar los metadatos de la propiedad del nivel de marco de WPF como parte de una llamada a OverrideMetadata o a AddOwner. Para obtener los valores específicos que se van a usar y otros datos, consulte Metadatos de las propiedades de marco de trabajo. Para obtener más información relativa a cómo deben establecerse estas opciones para una propiedad de dependencia recién registrada, consulte Propiedades de dependencia personalizadas.

Invalidar metadatos

El propósito de invalidar metadatos es principalmente que tenga la oportunidad de cambiar los distintos comportamientos derivados de metadatos que se aplican a la propiedad de dependencia tal como existe en el tipo. Las razones para ello se explican con más detalle en la sección Metadatos. Para obtener más información, incluidos algunos ejemplos de código, consulte Invalidar metadatos en una propiedad de dependencia.

Se pueden proporcionar los metadatos de propiedad de una propiedad de dependencia durante la llamada de registro (Register). Sin embargo, en muchos casos, es posible que quiera proporcionar metadatos específicos del tipo para la clase cuando esta herede esa propiedad de dependencia. Puede hacerlo llamando al método OverrideMetadata. Para obtener un ejemplo de las API de WPF, la clase FrameworkElement es el tipo que registra la propiedad de dependencia Focusable en primer lugar. Pero la clase Control invalida los metadatos de la propiedad de dependencia para proporcionar su propio valor predeterminado inicial, que cambia de false a true y, en caso contrario, vuelve a usar la implementación de Focusable original.

Si invalida los metadatos, las distintas características de los metadatos se combinan o se reemplazan.

  • PropertyChangedCallback se combina. Si agrega un elemento PropertyChangedCallback nuevo, esa devolución de llamada se almacena en los metadatos. Si no especifica un elemento PropertyChangedCallback en la invalidación, el valor de PropertyChangedCallback se promueve como referencia del antecesor más próximo que se haya especificado en los metadatos.

  • El comportamiento real del sistema de propiedades para PropertyChangedCallback es que las implementaciones de todos los propietarios de metadatos de la jerarquía se conserven y se agreguen a una tabla, de forma que el orden de ejecución en el sistema de propiedades consista en que se invoquen primero las devoluciones de llamada de la clase más derivadas.

  • DefaultValue se reemplaza. Si no especifica un elemento DefaultValue en la invalidación, el valor de DefaultValue procede del antecesor más próximo que se haya especificado en los metadatos.

  • Las implementaciones de CoerceValueCallback se reemplazan. Si agrega un elemento CoerceValueCallback nuevo, esa devolución de llamada se almacena en los metadatos. Si no especifica un elemento CoerceValueCallback en la invalidación, el valor de CoerceValueCallback se promueve como referencia del antecesor más próximo que se haya especificado en los metadatos.

  • El comportamiento del sistema de propiedades es que solo se invoque CoerceValueCallback en los metadatos inmediatos. No se conserva ninguna referencia a otras implementaciones de CoerceValueCallback en la jerarquía.

Este comportamiento se implementa mediante Merge y se puede invalidar en clases de metadatos derivadas.

Invalidar los metadatos de las propiedades adjuntas

En WPF, las propiedades adjuntas se implementan como propiedades de dependencia. Esto significa que también tienen metadatos de propiedad, que las clases individuales pueden invalidar. Por lo general, las consideraciones de ámbito de una propiedad adjunta en WPF son que cualquier DependencyObject puede tener una propiedad adjunta establecida. Por lo tanto, cualquier clase derivada de DependencyObject puede invalidar los metadatos de cualquier propiedad adjunta, ya que podría estar establecida en una instancia de la clase. Puede invalidar valores predeterminados, devoluciones de llamada o propiedades de informes de características del nivel de marco de WPF. Si se establece la propiedad adjunta en una instancia de la clase, se aplicarán las características de invalidación de metadatos de propiedad. Por ejemplo, puede invalidar el valor predeterminado, de modo que el valor de invalidación se notifique como el valor de la propiedad adjunta en las instancias de la clase, siempre que la propiedad no esté establecida de otro modo.

Nota:

La propiedad Inherits no es relevante en las propiedades adjuntas.

Agregar una clase como propietaria de una propiedad de dependencia existente

Una clase se puede agregar a sí misma como propietaria de una propiedad de dependencia que ya se registró, para lo cual se debe usar el método AddOwner. Esto permite que la clase use una propiedad de dependencia que se registró originalmente para un tipo diferente. La clase que se agrega no suele ser una clase derivada del tipo que registró inicialmente esa propiedad de dependencia como propietaria. De hecho, esto permite que la clase y sus clases derivadas "hereden" una implementación de propiedad de dependencia sin que la clase propietaria original y la clase que se agrega estén en la misma jerarquía de clases real. Además, la clase que se agrega (y también todas las clases derivadas) pueden proporcionar metadatos específicos del tipo para la propiedad de dependencia original.

Además de agregarse a sí misma como propietaria a través de los métodos de utilidad del sistema de propiedades, la clase que se agrega debe declarar miembros públicos adicionales en sí misma para convertir la propiedad de dependencia en un participante completo en el sistema de propiedades, con exposición para el código y la marcación. Una clase que agrega una propiedad de dependencia existente tiene las mismas responsabilidades en cuanto a exponer el modelo de objetos para esa propiedad de dependencia que una clase que define una nueva propiedad de dependencia personalizada. El primer miembro de este tipo que se va a exponer es un campo de identificador de propiedad de dependencia. Este campo debe ser un campo public static readonly de tipo DependencyProperty, que se asigne al valor devuelto de la llamada a AddOwner. El segundo miembro que se va a definir es la propiedad del "contenedor" de Common Language Runtime (CLR). El contenedor simplifica enormemente la manipulación de la propiedad de dependencia en el código (evita tener que llamar a SetValue cada vez, y la llamada se puede realizar una sola vez en el propio contenedor). El contenedor se implementa de forma idéntica a cómo se implementaría si se estuviera registrando una propiedad de dependencia personalizada. Para obtener más información acerca de cómo implementar una propiedad de dependencia, consulte Propiedades de dependencia personalizadas y Agregar un tipo de propietario para una propiedad de dependencia.

AddOwner y propiedades adjuntas

Se puede llamar a AddOwner en el caso de una propiedad de dependencia que la clase propietaria haya definido como propiedad adjunta. Generalmente, el motivo para hacerlo es exponer la propiedad adjunta anteriormente como una propiedad de dependencia no adjunta. Tras ello, expondrá el valor devuelto de AddOwner como un campo public static readonly para su uso como el identificador de la propiedad de dependencia y definirá las propiedades de "contenedor" adecuadas para que la propiedad aparezca en la tabla de miembros y admita el uso de una propiedad no adjunta en la clase.

Vea también