Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Los desarrolladores de aplicaciones y autores de componentes de Windows Presentation Foundation (WPF) pueden crear propiedades de dependencia personalizadas para ampliar la funcionalidad de sus propiedades. A diferencia de una propiedad de Common Language Runtime (CLR), una propiedad de dependencia agrega compatibilidad con estilos, enlaces de datos, herencia, animaciones y valores predeterminados. Background, Widthy Text son ejemplos de las propiedades de dependencia existentes en las clases de WPF. En este artículo se describe cómo implementar propiedades de dependencia personalizadas y se presentan opciones para mejorar el rendimiento, la facilidad de uso y la versatilidad.
Prerrequisitos
El artículo asume que tiene un conocimiento básico de las propiedades de dependencia y que ha leído Descripción general de las propiedades de dependencia. Para seguir los ejemplos de este artículo, le ayuda si está familiarizado con el lenguaje de marcado extensible de aplicaciones (XAML) y sabe cómo escribir aplicaciones WPF.
Identificador de propiedad de dependencia
Las propiedades de dependencia son propiedades registradas en el sistema de propiedades de WPF a través de llamadas Register o RegisterReadOnly. El Register
método devuelve una DependencyProperty instancia que contiene el nombre registrado y las características de una propiedad de dependencia. Asignará la DependencyProperty
instancia a un campo estático de solo lectura, conocido como identificador de propiedad de dependencia, que por convención se denomina <property name>Property
. Por ejemplo, el campo de identificador de la Background propiedad siempre es BackgroundProperty.
El identificador de propiedad de dependencia se usa como campo de respaldo para obtener o establecer valores de propiedad, en lugar del patrón estándar de respaldo de una propiedad con un campo privado. No solo el sistema de propiedades usa el identificador, los procesadores XAML pueden usarlo y el código (y posiblemente el código externo) puede tener acceso a las propiedades de dependencia a través de sus identificadores.
Las propiedades de dependencia solo se pueden aplicar a las clases derivadas de DependencyObject tipos. La mayoría de las clases de WPF admiten propiedades de dependencia, ya que DependencyObject
está cerca de la raíz de la jerarquía de clases de WPF. Para obtener más información sobre las propiedades de dependencia y la terminología y las convenciones que se usan para describirlas, consulte Introducción a las propiedades de dependencia.
Envoltorios de propiedades de dependencia
Las propiedades de dependencia de WPF que no son propiedades adjuntas se exponen mediante un contenedor CLR que implementa los descriptores de acceso get
y set
. Mediante el uso de un envoltorio de propiedades, los consumidores de propiedades de dependencia pueden obtener o establecer valores de propiedades de dependencia, igual que cualquier otra propiedad CLR. Los get
accesores y set
interactúan con el sistema de propiedades subyacente a través de llamadas a DependencyObject.GetValue y DependencyObject.SetValue, pasando el identificador de propiedad de dependencia como parámetro. Los consumidores de propiedades de dependencia normalmente no llaman a GetValue
ni a SetValue
directamente, pero si va a implementar una propiedad de dependencia personalizada, utilizará esos métodos en el contenedor.
Cuándo implementar una propiedad de dependencia
Cuando se implementa una propiedad en una clase que deriva de DependencyObject, se convierte en una propiedad de dependencia asociando su propiedad con un identificador DependencyProperty. Si es beneficioso crear una propiedad de dependencia depende de su escenario. Aunque respaldar su propiedad mediante un campo privado es adecuado para algunos escenarios, considere implementar una propiedad de dependencia si desea que su propiedad admita una o varias de las siguientes capacidades de WPF:
Propiedades que se pueden establecer dentro de un estilo. Para obtener más información, vea Estilos y plantillas.
Propiedades que admiten el enlace de datos. Para obtener más información sobre las propiedades de dependencia de enlace de datos, vea Enlazar las propiedades de dos controles.
Propiedades que se pueden establecer mediante referencias de recursos dinámicos. Para obtener más información, consulta Recursos XAML.
Propiedades que heredan automáticamente su valor de un elemento primario en el árbol de elementos. Para ello, debe registrarse usando RegisterAttached, incluso si también crea un envoltorio de propiedades para el acceso CLR. Para obtener más información, vea Herencia de valores de propiedad.
Propiedades que son animables. Para obtener más información, consulte Información general sobre animaciones.
Sistema de notificación de propiedades de WPF cuando cambia el valor de una propiedad. Los cambios pueden deberse a acciones del sistema de propiedades, el entorno, el usuario o los estilos. La propiedad puede especificar un método de devolución de llamada en los metadatos de propiedad que se invocarán cada vez que el sistema de propiedades observe que el valor de la propiedad ha cambiado. Un concepto relacionado es la coerción de valores de propiedad. Para obtener más información, consulte Callbacks y validación de propiedades dependientes.
Acceso a los metadatos de la propiedad de dependencia, que los procesos de WPF leen. Por ejemplo, puede usar metadatos de propiedad para:
Especifique si un valor de propiedad de dependencia modificado debe hacer que el sistema de diseño vuelva a componer los objetos visuales de un elemento.
Establezca el valor predeterminado de una propiedad de dependencia reemplazando los metadatos en las clases derivadas.
Compatibilidad con el diseñador WPF de Visual Studio, como editar las propiedades de un control personalizado en la ventana Propiedades. Para obtener más información, consulte Información general sobre la creación de controles.
En algunos escenarios, invalidar los metadatos de una propiedad de dependencia existente es una opción mejor que implementar una nueva propiedad de dependencia. Si una invalidación de metadatos es práctica depende de qué tan similar es su escenario a la implementación de las clases y propiedades de dependencia existentes de WPF. Para obtener más información sobre cómo invalidar metadatos en las propiedades de dependencia existentes, consulte Metadatos de propiedad de dependencia.
Lista de comprobación para crear una propiedad de dependencia
Siga estos pasos para crear una propiedad de dependencia. Algunos de los pasos se pueden combinar e implementar en una sola línea de código.
(Opcional) Cree metadatos para la propiedad de dependencia.
Registre la propiedad de dependencia con el sistema de propiedades, especificando un nombre de propiedad, un tipo de propietario, el tipo de valor de propiedad y, opcionalmente, los metadatos de propiedad.
Define un DependencyProperty identificador como un
public static readonly
campo del tipo propietario. El nombre del campo de identificador es el nombre de propiedad con el sufijoProperty
anexado.Defina una propiedad contenedora CLR que tenga el mismo nombre que la propiedad de dependencia. En el envoltorio CLR, implemente
get
yset
accesores que se conecten con la propiedad de dependencia que respalda el envoltorio.
Registro de la propiedad
Para que su propiedad sea una propiedad de dependencia, debe registrarla en el sistema de propiedades. Para registrar tu propiedad, llama al método Register dentro del cuerpo de tu clase, pero fuera de cualquier definición de miembros. El Register
método devuelve un identificador de propiedad de dependencia único que usará al llamar a la API del sistema de propiedades. La razón por la que la Register
llamada se realiza fuera de las definiciones de miembro es porque asigna el valor devuelto a un public static readonly
campo de tipo DependencyProperty. Este campo, que creará en su clase, es el identificador de su propiedad dependiente. En el ejemplo siguiente, el primer argumento de Register
asigna nombres a la propiedad AquariumGraphic
de dependencia .
// Register a dependency property with the specified property name,
// property type, owner type, and property metadata. Store the dependency
// property identifier as a public static readonly member of the class.
public static readonly DependencyProperty AquariumGraphicProperty =
DependencyProperty.Register(
name: "AquariumGraphic",
propertyType: typeof(Uri),
ownerType: typeof(Aquarium),
typeMetadata: new FrameworkPropertyMetadata(
defaultValue: new Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags: FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback: new PropertyChangedCallback(OnUriChanged))
);
' Register a dependency property with the specified property name,
' property type, owner type, and property metadata. Store the dependency
' property identifier as a public static readonly member of the class.
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty =
DependencyProperty.Register(
name:="AquariumGraphic",
propertyType:=GetType(Uri),
ownerType:=GetType(Aquarium),
typeMetadata:=New FrameworkPropertyMetadata(
defaultValue:=New Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags:=FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnUriChanged)))
Nota:
Definir la propiedad de dependencia en el cuerpo de la clase es la implementación típica, pero también es posible definir una propiedad de dependencia en el constructor estático de clase. Este enfoque puede tener sentido si necesita más de una línea de código para inicializar la propiedad de dependencia.
Nomenclatura de propiedades de dependencia
La convención de nomenclatura establecida para las propiedades de dependencia es obligatoria para el comportamiento normal del sistema de propiedades. El nombre del campo de identificador que cree debe ser el nombre registrado de la propiedad con el sufijo Property
.
Un nombre de propiedad de dependencia debe ser único dentro de la clase de registro. Las propiedades de dependencia que se heredan a través de un tipo base ya se han registrado y no se pueden registrar mediante un tipo derivado. Sin embargo, puede usar una propiedad de dependencia registrada por un tipo diferente, incluso un tipo del que la clase no hereda, agregando la clase como propietario de la propiedad de dependencia. Para obtener más información sobre cómo agregar una clase como propietario, consulte Metadatos de propiedad de dependencia.
Implementación de un envoltorio de propiedad
Por convención, el nombre de la propiedad contenedora debe ser el mismo que el primer parámetro de la Register llamada, que es el nombre de la propiedad de dependencia. La implementación del envoltorio llamará a GetValue en el descriptor de acceso get
y a SetValue en el descriptor de acceso set
(para propiedades de lectura y escritura). En el ejemplo siguiente se muestra un envoltorio—siguiendo la llamada de registro y la declaración del campo de identificador. Todas las propiedades de dependencia públicas de las clases WPF usan un modelo contenedor similar.
// Register a dependency property with the specified property name,
// property type, owner type, and property metadata. Store the dependency
// property identifier as a public static readonly member of the class.
public static readonly DependencyProperty AquariumGraphicProperty =
DependencyProperty.Register(
name: "AquariumGraphic",
propertyType: typeof(Uri),
ownerType: typeof(Aquarium),
typeMetadata: new FrameworkPropertyMetadata(
defaultValue: new Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags: FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback: new PropertyChangedCallback(OnUriChanged))
);
// Declare a read-write property wrapper.
public Uri AquariumGraphic
{
get => (Uri)GetValue(AquariumGraphicProperty);
set => SetValue(AquariumGraphicProperty, value);
}
' Register a dependency property with the specified property name,
' property type, owner type, and property metadata. Store the dependency
' property identifier as a public static readonly member of the class.
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty =
DependencyProperty.Register(
name:="AquariumGraphic",
propertyType:=GetType(Uri),
ownerType:=GetType(Aquarium),
typeMetadata:=New FrameworkPropertyMetadata(
defaultValue:=New Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags:=FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnUriChanged)))
' Declare a read-write property wrapper.
Public Property AquariumGraphic As Uri
Get
Return CType(GetValue(AquariumGraphicProperty), Uri)
End Get
Set
SetValue(AquariumGraphicProperty, Value)
End Set
End Property
Excepto en raras ocasiones, la implementación del envoltorio solo debe contener código GetValue y SetValue. Por los motivos subyacentes, consulte Implicaciones para las propiedades de dependencia personalizadas.
Si la propiedad no sigue las convenciones de nomenclatura establecidas, puede encontrarse con estos problemas:
Algunos aspectos de los estilos y plantillas no funcionarán.
La mayoría de las herramientas y diseñadores se basan en las convenciones de nomenclatura para serializar XAML correctamente y proporcionar asistencia al entorno de diseñador en un nivel por propiedad.
La implementación actual del cargador XAML de WPF omite completamente los contenedores y se basa en la convención de nomenclatura para procesar los valores de atributo. Para obtener más información, consulta Propiedades de carga y dependencia de XAML.
Metadatos de propiedad de dependencia
Al registrar una propiedad de dependencia, el sistema de propiedades crea un objeto de metadatos para almacenar las características de propiedad. Las sobrecargas del método Register te permiten especificar metadatos de propiedad durante el registro, por ejemplo Register(String, Type, Type, PropertyMetadata). Un uso común de los metadatos de propiedad es aplicar un valor predeterminado personalizado para las nuevas instancias que usan una propiedad de dependencia. Si no proporciona metadatos de propiedad, el sistema de propiedades asignará valores predeterminados a muchas de las características de la propiedad de dependencia.
Si va a crear una propiedad de dependencia en una clase derivada de FrameworkElement, puede usar la clase FrameworkPropertyMetadata de metadatos más especializada en lugar de su clase PropertyMetadatabase . Varias FrameworkPropertyMetadata firmas de constructor permiten especificar diferentes combinaciones de características de metadatos. Si solo desea especificar un valor predeterminado, use FrameworkPropertyMetadata(Object) y pase el valor predeterminado al Object
parámetro . Asegúrese de que el tipo de valor coincide con el propertyType
especificado en la Register
llamada.
Algunas FrameworkPropertyMetadata sobrecargas permiten especificar banderas de opciones de metadatos para su propiedad. El sistema de propiedades convierte estas marcas en propiedades discretas y los valores de marca los usan los procesos de WPF, como el motor de diseño.
Establecimiento de marcas de metadatos
Tenga en cuenta lo siguiente al establecer marcas de metadatos:
Si el valor de la propiedad (o los cambios en él) afecta cómo el sistema de diseño renderiza un elemento de la interfaz de usuario, establezca una o más de las siguientes banderas:
AffectsMeasure, que indica que un cambio en el valor de propiedad requiere un cambio en la representación de la interfaz de usuario, específicamente el espacio ocupado por un objeto dentro de su elemento primario. Por ejemplo, establezca esta marca de metadatos para una
Width
propiedad .AffectsArrange, que indica que un cambio en el valor de propiedad requiere un cambio en la representación de la interfaz de usuario, específicamente la posición de un objeto dentro de su elemento primario. Normalmente, el objeto tampoco cambia el tamaño. Por ejemplo, establezca esta marca de metadatos para una
Alignment
propiedad .AffectsRender, que indica que se ha producido un cambio que no afecta al diseño y la medida, pero aún requiere otra representación. Por ejemplo, establezca esta marca para una
Background
propiedad o cualquier otra propiedad que afecte al color de un elemento.
También puede utilizar estas banderas como entradas para sus implementaciones de sobrescritura de los callbacks del sistema de propiedades (o del diseño). Por ejemplo, puede usar una OnPropertyChanged devolución de llamada para llamar a InvalidateArrange cuando una propiedad del objeto informa un cambio de valor y tiene AffectsArrange configurado en los metadatos.
Algunas propiedades afectan a las características de representación de su elemento primario de otras maneras. Por ejemplo, los cambios en la MinOrphanLines propiedad pueden cambiar la representación general de un documento de flujo. Use AffectsParentArrange o AffectsParentMeasure para indicar acciones primarias en sus propias propiedades.
De forma predeterminada, las propiedades de dependencia admiten el enlace de datos. Sin embargo, puede usar IsDataBindingAllowed para deshabilitar el enlace de datos cuando no hay ningún escenario realista para él o donde el rendimiento del enlace de datos es problemático, como en objetos grandes.
Aunque el modo de enlace de datos predeterminado para las propiedades de dependencia es OneWay, puede cambiar el modo de enlace de un enlace específico a TwoWay. Para obtener más información, vea Dirección de vinculación. Como autor de propiedades de dependencia, incluso puede optar por establecer la vinculación bidireccional como modo predeterminado. Un ejemplo de una propiedad de dependencia existente que usa el enlace de datos bidireccional es MenuItem.IsSubmenuOpen, que tiene un estado basado en otras propiedades y llamadas de método. El escenario de
IsSubmenuOpen
es que su lógica de configuración y la composición de MenuItem, interactúan con el estilo de tema predeterminado. TextBox.Text es otra propiedad de dependencia de WPF que usa el enlace bidireccional de forma predeterminada.Puede habilitar la herencia de propiedades para su propiedad de dependencia estableciendo el indicador Inherits. La herencia de propiedades es útil para escenarios en los que los elementos primarios y secundarios tienen una propiedad en común y tiene sentido que el elemento secundario herede el valor primario de la propiedad común. Un ejemplo de una propiedad heredable es DataContext, que admite operaciones de enlace que usan el escenario master-detail.
Establezca el indicador Journal para indicar que su propiedad de dependencia debe ser detectada o utilizada por los servicios de registro en diario de navegación. Por ejemplo, la SelectedIndex propiedad establece la
Journal
bandera para recomendar que las aplicaciones conserven un historial de los elementos seleccionados.
Propiedades de dependencia de solo lectura
Puede definir una propiedad de dependencia que sea de solo lectura. Un escenario típico es una propiedad de dependencia que almacena el estado interno. Por ejemplo, IsMouseOver es de solo lectura porque su estado solo debe determinarse mediante la entrada del mouse. Para obtener más información, consulte Propiedades de dependencia de solo lectura.
Propiedades de dependencia de tipo de colección
Las propiedades de dependencia de tipo de colección tienen problemas de implementación adicionales que se deben tener en cuenta, como establecer un valor predeterminado para los tipos de referencia y la compatibilidad con el enlace de datos para los elementos de colección. Para obtener más información, vea Propiedades de dependencia de tipo de colección.
Seguridad de las propiedades de dependencia
Normalmente, declarará propiedades de dependencia como propiedades públicas y DependencyProperty identificará campos como public static readonly
. Si especifica un nivel de acceso más restrictivo, como protected
, todavía se puede acceder a una propiedad de dependencia a través de su identificador en combinación con las API del sistema de propiedades. Incluso un campo de identificador protegido es posiblemente accesible a través de las API de determinación de valores o informes de metadatos de WPF, como LocalValueEnumerator. Para obtener más información, consulte Seguridad de propiedades de dependencia.
En el caso de las propiedades de dependencia de solo lectura, el valor devuelto de RegisterReadOnly es DependencyPropertyKey, y normalmente no hará de DependencyPropertyKey
un miembro de su clase. Dado que el sistema de propiedades de WPF no propaga el DependencyPropertyKey
fuera de tu código, una propiedad de dependencia de solo lectura tiene mayor set
seguridad que una propiedad de dependencia de lectura y escritura.
Propiedades de dependencia y constructores de clases
Hay un principio general en la programación de código administrado, a menudo aplicado por las herramientas de análisis de código, que los constructores de clase no deben llamar a métodos virtuales. Esto se debe a que se puede llamar a constructores base durante la inicialización de un constructor de clase derivada y un método virtual llamado por un constructor base podría ejecutarse antes de completar la inicialización de la clase derivada. Cuando se deriva de una clase que ya deriva de DependencyObject, el sistema de propiedades en sí mismo llama y expone métodos virtuales internamente. Estos métodos virtuales forman parte de los servicios del sistema de propiedades de WPF. La invalidación de los métodos permite que las clases derivadas participen en la determinación del valor. Para evitar posibles problemas con la inicialización en tiempo de ejecución, no debe establecer valores de propiedad de dependencia en constructores de clases, a menos que siga un patrón de constructor específico. Para obtener más información, vea Patrones de constructor seguros para DependencyObjects.
Consulte también
- Información general sobre las propiedades de dependencia
- Metadatos de propiedad de dependencia
- Información general sobre la creación de controles
- Propiedades de dependencia de tipo de colección
- Seguridad de las propiedades de dependencia
- Propiedades de carga y dependencia de XAML
- Patrones de constructor seguros para DependencyObjects
.NET Desktop feedback