wpf
Propiedades de dependencia
Buscar..
Introducción
Las propiedades de dependencia son un tipo de propiedad que se extiende a una propiedad CLR. Mientras que una propiedad CLR se lee directamente de un miembro de su clase, una Propiedad de dependencia se resolverá dinámicamente al llamar al método GetValue () que su objeto obtiene a través de la herencia de la clase DependencyObject básica.
Esta sección desglosará las Propiedades de dependencia y explicará su uso tanto a nivel conceptual como a través de ejemplos de código.
Sintaxis
- DependencyProperty.Register (nombre de cadena, Type propertyType, Type ownerType)
- DependencyProperty.Register (nombre de cadena, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.Register (nombre de cadena, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
- DependencyProperty.RegisterAttached (nombre de cadena, tipo propertyType, tipo ownerType)
- DependencyProperty.RegisterAttached (nombre de cadena, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.RegisterAttached (nombre de cadena, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
- DependencyProperty.RegisterReadOnly (nombre de cadena, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.RegisterReadOnly (nombre de cadena, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
- DependencyProperty.RegisterAttachedReadOnly (nombre de cadena, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.RegisterAttachedReadOnly (nombre de cadena, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
Parámetros
Parámetro | Detalles |
---|---|
nombre | La representación en String del nombre de la propiedad. |
tipo de propiedad | El Type de la propiedad, por ejemplo, typeof(int) |
ownerType | El Type de la clase en la que se define la propiedad, por ejemplo, typeof(MyControl) o typeof(MyAttachedProperties) . |
typeMetadata | Instancia de System.Windows.PropertyMetadata (o una de sus subclases) que define valores predeterminados, devoluciones de llamada modificadas de propiedad, FrameworkPropertyMetadata permite definir opciones de enlace como System.Windows.Data.BindingMode.TwoWay . |
validateValueCallback | Devolución de llamada personalizada que devuelve verdadero si el nuevo valor de la propiedad es válido, de lo contrario es falso. |
Propiedades de dependencia estándar
Cuándo usar
Prácticamente todos los controles de WPF hacen un uso intensivo de las propiedades de dependencia. Una propiedad de dependencia permite el uso de muchas características de WPF que no son posibles solo con las propiedades CLR estándar, incluidas, entre otras, la compatibilidad con estilos, animaciones, enlace de datos, herencia de valores y notificaciones de cambios.
La propiedad TextBox.Text
es un ejemplo simple de dónde se necesita una propiedad de dependencia estándar. Aquí, el enlace de datos no sería posible si el Text
fuera una propiedad CLR estándar.
<TextBox Text="{Binding FirstName}" />
Como definir
Las propiedades de dependencia solo se pueden definir en clases derivadas de DependencyObject
, como FrameworkElement
, Control
, etc.
Una de las formas más rápidas de crear una propiedad de dependencia estándar sin tener que recordar la sintaxis es usar el fragmento "propdp" escribiendo propdp
y luego presionando Tab . Se insertará un fragmento de código que luego se puede modificar para satisfacer sus necesidades:
public class MyControl : Control
{
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty.
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl),
new PropertyMetadata(0));
}
Debe desplazarse por las diferentes partes del fragmento de código para realizar los cambios necesarios, incluida la actualización del nombre de la propiedad, el tipo de propiedad, el tipo de clase y el valor predeterminado.
Convenciones importantes
Hay algunas convenciones / reglas importantes a seguir aquí:
Cree una propiedad CLR para la propiedad de dependencia. Esta propiedad se utiliza en el código subyacente de su objeto o por otros consumidores. Debe invocar
GetValue
ySetValue
para que los consumidores no tengan que hacerlo.Nombre la propiedad de dependencia correctamente. El campo
DependencyProperty
debe serpublic static readonly
. Debe tener un nombre que se corresponda con el nombre de la propiedad CLR y termine con "Propiedad", por ejemplo,Text
yTextProperty
Text
.No agregue lógica adicional al definidor de la propiedad CLR. El sistema de propiedades de dependencia (y XAML específicamente) no hace uso de la propiedad CLR. Si desea realizar una acción cuando cambia el valor de la propiedad, debe proporcionar una devolución de llamada a través de
PropertyMetadata
:public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl), new PropertyMetadata(0, MyPropertyChangedHandler)); private static void MyPropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs args) { // Use args.OldValue and args.NewValue here as needed. // sender is the object whose property changed. // Some unboxing required. }
Modo de encuadernación
Para eliminar la necesidad de especificar Mode=TwoWay
en los enlaces (similar al comportamiento de TextBox.Text
), actualice el código para usar FrameworkPropertyMetadata
lugar de PropertyMetadata
y especifique la TextBox.Text
correspondiente:
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
Propiedades de dependencia adjuntas
Cuándo usar
Una propiedad adjunta es una propiedad de dependencia que se puede aplicar a cualquier DependencyObject
para mejorar el comportamiento de varios controles o servicios que son conscientes de la existencia de la propiedad.
Algunos casos de uso para propiedades adjuntas incluyen:
- Tener un elemento padre iterar a través de sus hijos y actuar sobre los niños de cierta manera. Por ejemplo, el control
Grid
usa lasGrid.Row
Grid.Column
Grid.Row
,Grid.Column
,Grid.RowSpan
yGrid.ColumnSpan
para organizar los elementos en filas y columnas. - Agregar elementos visuales a controles existentes con plantillas personalizadas, por ejemplo, agregar marcas de agua a cuadros de texto vacíos en toda la aplicación sin tener que subclasificar
TextBox
. - Proporcionar un servicio o característica genérica a algunos o todos los controles existentes, por ejemplo,
ToolTipService
oFocusManager
. Estos se conocen comúnmente como comportamientos adjuntos . - Cuando se requiere la herencia del árbol visual, por ejemplo, similar al comportamiento de
DataContext
.
Esto demuestra aún más lo que está sucediendo en el caso de uso de Grid
:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="Your Name:" />
<TextBox Grid.Column="1" Text="{Binding FirstName}" />
</Grid>
Grid.Column
no es una propiedad que exista en Label
o TextBox
. Más bien, el control de Grid
examina sus elementos secundarios y los organiza de acuerdo con los valores de las propiedades adjuntas.
Como definir
Continuaremos usando Grid
para este ejemplo. La definición de Grid.Column
se muestra a continuación, pero se excluye DependencyPropertyChangedEventHandler
por brevedad.
public static readonly DependencyProperty RowProperty =
DependencyProperty.RegisterAttached("Row", typeof(int), typeof(Grid),
new FrameworkPropertyMetadata(0, ...));
public static void SetRow(UIElement element, int value)
{
if (element == null)
throw new ArgumentNullException("element");
element.SetValue(RowProperty, value);
}
public static int GetRow(UIElement element)
{
if (element == null)
throw new ArgumentNullException("element");
return ((int)element.GetValue(RowProperty));
}
Debido a que las propiedades adjuntas se pueden adjuntar a una amplia variedad de elementos, no se pueden implementar como propiedades CLR. Un par de métodos estáticos se introduce en su lugar.
Por lo tanto, a diferencia de las propiedades de dependencia estándar, las propiedades adjuntas también se pueden definir en clases que no se derivan de DependencyObject
.
Las mismas convenciones de nomenclatura que se aplican a las propiedades de dependencia regulares también se aplican aquí: la propiedad de dependencia RowProperty
tiene los métodos correspondientes GetRow
y SetRow
.
Advertencias
Como se documenta en MSDN :
Aunque la herencia de valor de propiedad puede parecer que funciona para propiedades de dependencia no adjuntas, el comportamiento de herencia para una propiedad no asociada a través de ciertos límites de elementos en el árbol de tiempo de ejecución no está definido. Siempre use RegisterAttached para registrar propiedades donde especifique Herencias en los metadatos.
Propiedades de dependencia de solo lectura
Cuándo usar
Una propiedad de dependencia de solo lectura es similar a una propiedad de dependencia normal, pero está estructurada para no permitir que su valor se establezca desde fuera del control. Esto funciona bien si tiene una propiedad que es meramente informativa para los consumidores, por ejemplo, IsMouseOver
o IsKeyboardFocusWithin
.
Como definir
Al igual que las propiedades de dependencia estándar, una propiedad de dependencia de solo lectura debe definirse en una clase que se derive de DependencyObject
.
public class MyControl : Control
{
private static readonly DependencyPropertyKey MyPropertyPropertyKey =
DependencyProperty.RegisterReadOnly("MyProperty", typeof(int), typeof(MyControl),
new FrameworkPropertyMetadata(0));
public static readonly DependencyProperty MyPropertyProperty = MyPropertyPropertyKey.DependencyProperty;
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
private set { SetValue(MyPropertyPropertyKey, value); }
}
}
Las mismas convenciones que se aplican a las propiedades de dependencia regulares también se aplican aquí, pero con dos diferencias clave:
-
DependencyProperty
se obtiene de unDependencyPropertyKey
private
. - El establecedor de propiedades CLR está
protected
o esprivate
lugar depublic
.
Tenga en cuenta que el MyPropertyPropertyKey
pasa MyPropertyPropertyKey
y no MyPropertyProperty
al método SetValue
. Debido a que la propiedad se definió como de solo lectura, cualquier intento de usar SetValue
en la propiedad debe usarse con una sobrecarga que recibe DependencyPropertyKey
; de lo contrario, se InvalidOperationException
una InvalidOperationException
.