Información general sobre propiedades asociadas

Una propiedad adjunta es un concepto definido por XAML. Una propiedad adjunta está destinada a usarse como un tipo de propiedad global que se puede establecer en cualquier objeto de dependencia. En Windows Presentation Foundation (WPF) las propiedades adjuntas se definen normalmente como una forma especializada de propiedad de dependencia que no tiene el «contenedor» de propiedades convencional.

Requisitos previos

En este artículo se supone que entiende las propiedades de dependencia desde la perspectiva de un consumidor de propiedades de dependencia existentes en las clases de Windows Presentation Foundation (WPF), y que ha leído el tema Información general sobre las propiedades de dependencia. Para seguir los ejemplos de este artículo, también debe comprender el lenguaje XAML y saber cómo escribir aplicaciones WPF.

Motivos para usar las propiedades adjuntas

Un objetivo de una propiedad adjunta es permitir que distintos elementos secundarios especifiquen valores únicos para una propiedad que está definida en un elemento primario. Una aplicación concreta de este escenario es hacer que los elementos secundarios notifiquen al elemento primario cómo se presentarán en la interfaz de usuario (IU). Un ejemplo es la propiedad DockPanel.Dock. La propiedad DockPanel.Dock se crea como una propiedad adjunta porque está diseñada para ser establecida en elementos contenidos en un DockPanel, en lugar de en el mismo DockPanel. La clase DockPanel define un campo estático DependencyProperty denominado DockProperty y, a continuación, proporciona los métodos GetDock y SetDock como descriptores de acceso públicos para la propiedad adjunta.

Propiedades adjuntas en XAML

En XAML, las propiedades adjuntas se establecen mediante la sintaxis ProveedorDePropiedadAdjunta.NombreDePropiedad

A continuación se muestra un ejemplo de cómo puede establecer DockPanel.Dock en XAML:

<DockPanel>
    <TextBox DockPanel.Dock="Top">Enter text</TextBox>
</DockPanel>

El uso es similar al de una propiedad estática; siempre se hace referencia al tipo DockPanel que posee y registra la propiedad adjunta, en lugar de hacer referencia a cualquier instancia especificada por el nombre.

Además, dado que una propiedad adjunta en XAML es un atributo que se establece en el marcado, solamente la operación set tiene alguna relevancia. No se puede obtener directamente una propiedad en XAML, aunque hay algunos mecanismos indirectos para comparar valores, como los desencadenadores en estilos (para obtener más información, consulte Aplicar estilos y plantillas).

Implementación de propiedades adjuntas en WPF

En Windows Presentation Foundation (WPF), la mayoría de las propiedades adjuntas relacionadas con la IU en los tipos de WPF se implementan como propiedades de dependencia. Las propiedades adjuntas son un concepto de XAML, mientras que las propiedades de dependencia son un concepto de WPF. Dado que las propiedades adjuntas de WPF son propiedades de dependencia, admiten los conceptos de las propiedades de dependencia, tales como los metadatos de las propiedades y los valores predeterminados de dichos metadatos.

Uso de las propiedades adjuntas por el tipo de propiedad

Aunque las propiedades adjuntas se pueden establecer en cualquier objeto, eso no significa automáticamente que establecer la propiedad vaya a producir un resultado tangible ni que otro objeto no pueda usar nunca el valor. Por lo general, las propiedades adjuntas están diseñadas para que los objetos procedentes de una amplia variedad de posibles jerarquías de clases o relaciones lógicas puedan, individualmente, notificar información común del tipo que define la propiedad adjunta. El tipo que define la propiedad adjunta suele seguir uno de estos modelos:

  • El tipo que define la propiedad adjunta está diseñado para poder ser el elemento primario de los elementos que establecerán los valores de la propiedad adjunta. A continuación, el tipo itera sus objetos secundarios a través de la lógica interna en alguna estructura de árbol de objetos, obtiene los valores y actúa sobre esos valores de algún modo.

  • El tipo que define la propiedad adjunta se usará como el elemento secundario de una variedad de posibles elementos primarios y modelos de contenido.

  • El tipo que define la propiedad adjunta representa un servicio. Otros tipos establecen los valores de la propiedad adjunta. A continuación, cuando el elemento que establece la propiedad se evalúa en el contexto del servicio, los valores de la propiedad adjunta se obtienen a través de la lógica interna de la clase de servicio.

Ejemplo de una propiedad adjunta definida por el elemento primario

El escenario más típico donde WPF define una propiedad adjunta es aquel en que un elemento primario admite una colección de elementos secundarios e implementa un comportamiento donde se notifican individualmente los detalles del comportamiento de cada elemento secundario.

DockPanel define la propiedad adjunta DockPanel.Dock y DockPanel tiene código de nivel de clase como parte de su lógica de representación (en concreto, MeasureOverride y ArrangeOverride). Una instancia de DockPanel siempre comprobará si alguno de sus elementos secundarios inmediatos ha establecido un valor para DockPanel.Dock. Si es así, esos valores se convierten en la entrada de la lógica de representación que se aplica a ese elemento secundario determinado. Cada una de las instancias anidadas de DockPanel tratará las colecciones de su propio elemento secundario inmediato, pero ese comportamiento es específico a la implementación en cuanto a cómo procesa DockPanel los valores DockPanel.Dock. Teóricamente, es posible tener propiedades adjuntas que influyan en los elementos, más allá del elemento primario inmediato. Si la propiedad adjunta DockPanel.Dock se establece en un elemento que no tiene un elemento primario DockPanel sobre el que actuar, no se iniciará ningún error ni excepción. Esto significa, simplemente, que un valor de propiedad global está establecido, pero que en ese momento no tiene ningún elemento primario DockPanel que pueda consumir la información.

Propiedades adjuntas en el código

Las propiedades adjuntas de WPF no tienen los métodos «contenedor» típicos de CLR para el acceso fácil a Get o Set. Esto se debe a que la propiedad adjunta no forma parte necesariamente del espacio de nombres de CLR para las instancias donde se ha establecido la propiedad. No obstante, un procesador de XAML debe poder establecer esos valores durante el análisis de XAML. Para admitir el uso eficaz de las propiedades adjuntas, el tipo de propietario de la propiedad adjunta debe implementar métodos de descriptor de acceso dedicados de la forma GetPropertyName y SetPropertyName. Estos métodos de descriptor de acceso dedicados también resultan útiles para obtener o establecer la propiedad adjunta en el código. Desde una perspectiva del código, una propiedad adjunta se parece a un campo de respaldo, que presenta descriptores de acceso de métodos en lugar de descriptores de acceso de propiedades. Ese campo de respaldo puede existir en cualquier objeto, en lugar de tener que definirse específicamente.

En el ejemplo siguiente se muestra cómo establecer una propiedad adjunta en el código. En el ejemplo myCheckBox es una instancia de la clase CheckBox.

DockPanel myDockPanel = new DockPanel();
CheckBox myCheckBox = new CheckBox();
myCheckBox.Content = "Hello";
myDockPanel.Children.Add(myCheckBox);
DockPanel.SetDock(myCheckBox, Dock.Top);
Dim myDockPanel As New DockPanel()
Dim myCheckBox As New CheckBox()
myCheckBox.Content = "Hello"
myDockPanel.Children.Add(myCheckBox)
DockPanel.SetDock(myCheckBox, Dock.Top)

De manera similar al caso de XAML, si myCheckBox no se hubiera agregado todavía como un elemento secundario de myDockPanel mediante la cuarta línea de código, la quinta línea de código no iniciaría una excepción, pero el valor de propiedad no interactuaría con un elemento primario DockPanel y, por lo tanto, no haría nada. Solo un valor de DockPanel.Dock establecido en un elemento secundario combinado con la presencia de un elemento primario DockPanel generará un comportamiento eficaz en la aplicación representada. (En este caso se podría establecer la propiedad adjunta y, a continuación, adjuntarla al árbol. O bien, podría adjuntar al árbol y, a continuación, establecer la propiedad adjunta. Cualquier orden de acción proporciona el mismo resultado).

Metadatos de las propiedades adjuntas

Al registrar una propiedad adjunta, FrameworkPropertyMetadata se establece para especificar las características de la propiedad, como, por ejemplo, si la propiedad afecta o no a la representación, a la medida, etc. Los metadatos de una propiedad adjunta no suelen ser diferentes de los de una propiedad de dependencia. Si especifica un valor predeterminado de una invalidación en los metadatos de la propiedad adjunta, ese valor se convierte en el valor predeterminado de la propiedad adjunta implícita en las instancias de la clase de invalidación. En concreto, su valor predeterminado se notifica si algún proceso consulta el valor de una propiedad adjunta a través del descriptor de acceso del método Get de esa propiedad y especifica una instancia de la clase donde se especificaron los metadatos, y el valor de esa propiedad asociada no estaba establecido.

Si quiere habilitar la herencia de valores de propiedad en una propiedad, debe utilizar las propiedades adjuntas en lugar de propiedades de dependencia no adjuntas. Para obtener información detallada, consulte Herencia de valores de propiedad.

Propiedades adjuntas personalizadas

Cuándo crear una propiedad adjunta

Puede crear una propiedad adjunta cuando existe una razón para tener una mecanismo de definición de propiedades disponible para clases distintas de la clase que se define. El escenario más común es el diseño. Ejemplos de propiedades de diseño existentes are DockPanel.Dock, Panel.ZIndex y Canvas.Top. El escenario habilitado aquí es que los elementos que existen como elementos secundarios de los elementos que controlan el diseño pueden expresar los requisitos de diseño para sus elementos primarios de diseño individualmente, cada uno de los cuales define un valor de propiedad para el elemento primario definido como una propiedad adjunta.

Otro escenario para usar una propiedad adjunta es cuando la clase representa un servicio y quiere que las clases puedan integrar el servicio de manera más transparente.

Otro escenario es recibir soporte técnico de WPF Designer de Visual Studio, como la edición de la ventana Propiedades. Para obtener más información, consulte Información general sobre la creación de controles.

Como mencionamos anteriormente, debe realizar el registro como una propiedad adjunta si quiere usar la herencia de valores de propiedad.

Cómo crear una propiedad adjunta

Si la clase está definiendo la propiedad adjunta estrictamente para su uso en otros tipos, la clase no tiene que derivar de DependencyObject. No obstante, tiene que derivar de DependencyObject si sigue el modelo general de WPF según el cual la propiedad adjunta también debe ser una propiedad de dependencia.

Defina la propiedad adjunta como una dependencia declarando un campo public static readonly de tipo DependencyProperty. Este campo se define mediante el uso del valor que devuelve el método RegisterAttached. El nombre del campo debe coincidir con el nombre de la propiedad adjunta, con la cadena Property anexada, para seguir el patrón establecido de WPF para la nomenclatura de campos de identificación frente a las propiedades que representan. El proveedor de propiedades adjuntas debe proporcionar también los métodos estáticos GetPropertyName y SetPropertyName como descriptores de acceso para la propiedad adjunta; de lo contrario, el sistema de propiedades no podrá usar la propiedad adjunta.

Nota:

Si omite el descriptor de acceso Get de la propiedad adjunta, el enlace de datos en la propiedad no funcionará en las herramientas de diseño como Visual Studio y Blend for Visual Studio.

Descriptor de acceso get

La signatura del descriptor de acceso GetPropertyName debe ser:

public static object GetPropertyName(object target)

  • El objeto target puede especificarse como un tipo más específico en la implementación. Por ejemplo, el método DockPanel.GetDock escribe el parámetro como UIElement porque la propiedad adjunta solo está destinada a ser establecida en instancias de UIElement.

  • El valor devuelto puede especificarse como un tipo más específico en la implementación. Por ejemplo, el método GetDock lo escribe como Dock porque el valor solo se puede establecer en esa enumeración.

Descriptor de acceso set

La signatura del descriptor de acceso SetPropertyName debe ser:

public static void SetPropertyName(object target, object value)

  • El objeto target puede especificarse como un tipo más específico en la implementación. Por ejemplo, el método SetDock lo escribe como UIElement porque la propiedad adjunta está diseñada para establecerse solo en instancias de UIElement.

  • El objeto value puede especificarse como un tipo más específico en la implementación. Por ejemplo, el método SetDock lo escribe como Dock porque el valor solo se puede establecer en esa enumeración. Recuerde que el valor de este método es la entrada procedente del cargador de XAML cuando encuentra la propiedad adjunta en el uso de propiedades adjuntas en un marcado. Esa entrada es el valor especificado como un valor de atributo XAML en el marcado. Por lo tanto, debe existir compatibilidad con la conversión de tipos, el serializador de valores o la extensión de marcado para el tipo que usa, de modo que el tipo adecuado se pueda crear desde el valor del atributo (que, básicamente, es una cadena).

En el siguiente ejemplo se muestra el registro de propiedades de dependencia (con el método RegisterAttached), así como los descriptores de acceso GetPropertyName y SetPropertyName. En el ejemplo, el nombre de la propiedad adjunta es IsBubbleSource. Por consiguiente, los descriptores de acceso deben denominarse GetIsBubbleSource y SetIsBubbleSource.

public static readonly DependencyProperty IsBubbleSourceProperty = DependencyProperty.RegisterAttached(
  "IsBubbleSource",
  typeof(Boolean),
  typeof(AquariumObject),
  new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
  element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
  return (Boolean)element.GetValue(IsBubbleSourceProperty);
}
Public Shared ReadOnly IsBubbleSourceProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsBubbleSource", GetType(Boolean), GetType(AquariumObject), New FrameworkPropertyMetadata(False, FrameworkPropertyMetadataOptions.AffectsRender))
Public Shared Sub SetIsBubbleSource(ByVal element As UIElement, ByVal value As Boolean)
    element.SetValue(IsBubbleSourceProperty, value)
End Sub
Public Shared Function GetIsBubbleSource(ByVal element As UIElement) As Boolean
    Return CType(element.GetValue(IsBubbleSourceProperty), Boolean)
End Function

Atributos de propiedades adjuntas

WPF define varios atributos de .NET diseñados para proporcionar información sobre las propiedades adjuntas a los procesos de reflexión y a los usuarios habituales de la reflexión y la información de propiedades, tales como diseñadores. Dado que las propiedades adjuntas tienen un tipo de ámbito ilimitado, los diseñadores necesitan una manera de evitar abrumar a los usuarios con una lista global de todas las propiedades adjuntas que se definen en una implementación de tecnología específica que utiliza XAML. Los atributos de .NET que define WPF para las propiedades adjuntas se pueden usar para delimitar las situaciones donde una propiedad adjunta determinada debería mostrarse en una ventana de propiedades. También puede aplicar estos atributos para sus propias propiedades adjuntas personalizadas. El propósito y la sintaxis de los atributos de .NET se describen en las páginas de referencia correspondientes:

Más información sobre las propiedades adjuntas

  • Para obtener más información acerca de cómo crear una propiedad adjunta, consulte Registrar una propiedad asociada.

  • Para obtener escenarios de uso más avanzados sobre las propiedades de dependencia y las propiedades adjuntas, consulte Propiedades de dependencia personalizadas.

  • Puede registrar una propiedad como una propiedad adjunta y también como una propiedad de dependencia, pero continuar exponiendo las implementaciones de "contenedor". En este caso, la propiedad puede establecerse en ese elemento o en cualquier elemento a través de la sintaxis XAML de la propiedad adjunta. Un ejemplo de una propiedad con un escenario adecuado para los usos estándar y adjunto es FrameworkElement.FlowDirection.

Vea también