.net wpf silverlight dependency-properties

.net - Desmitificando propiedades de dependencia



wpf silverlight (7)

He leído mucho sobre las propiedades de dependencia en SO y otros sitios. Pero, realmente no he encontrado una gran explicación y todavía estoy confundido. Yo uso tanto SL como WPF. ¿Son diferentes en SL y WPF, en términos de implementación? ¿Por qué los necesitamos realmente? ¿Son estáticos significa que sus valores son compartidos? ¿Por qué la razón por la que MS introdujo las propiedades de dependencia?

Recompensa: Estoy buscando una respuesta más completa y completa.


  1. ¿Son diferentes en SL y WPF?
    No

  2. ¿Por qué los necesitamos realmente?
    La respuesta corta es que los necesitamos para el enlace de datos y el estilo, y es por eso que fueron agregados por MS.

  3. ¿Son estáticos significa que sus valores son compartidos?
    La parte estática es el nombre de la propiedad, por lo que puede recuperarse con GetValue (propName) y configurarse con SetValue (propName, value)


La mayoría de las preguntas que plantearon han sido respondidas por otros, pero les daré mi opinión simple sobre ellas.

Primero, son diferentes entre Silverlight y WPF, ya que las propiedades de dependencia de WPF tienen más capacidades. Sin embargo, excluyendo estas capacidades adicionales en WPF, son fundamentalmente las mismas.

La gran pregunta es "cuándo" debe usarlos (el "por qué" ya ha sido respondido en su mayoría). Básicamente, los necesita cuando necesita asignarles una extensión de marcado en XAML (como una expresión de enlace), que luego se resolverá / evaluará en tiempo de ejecución. Durante la mayor parte del tiempo, esto solo será necesario al escribir controles personalizados que expongan las propiedades.

es decir, suelta un control personalizado en una superficie en XAML y asigna una expresión de enlace a una de sus propiedades.

Veo que algunas personas los utilizan en todas partes, pensando que son necesarios al realizar el desarrollo de Silverlight / WPF, pero este no es el caso. Diferentes personas tienen diferentes líneas que dibujan en la arena, pero yo digo que solo las use cuando sea necesario, que casi el 100% del tiempo está dentro de los controles personalizados.

Autopromoción blantante: Tengo una discusión más profunda (específica de Silverlight) sobre este tema en el capítulo 10 de mi libro Pro Business Applications en Silverlight 4 .


La respuesta está en el propio nombre, aunque la palabra "dependencia" está tan cargada de significado en el desarrollo de software que no está especialmente claro lo que eso significa.

Una propiedad de dependencia es una propiedad de un objeto cuyo valor depende de algún otro objeto. Entonces, por ejemplo:

  • El valor de la propiedad FontFamily de un TextBox puede (y generalmente depende) de la propiedad FontFamily de su contenedor. Si cambia la propiedad en el contenedor, el valor en el TextBox cambia.

  • El valor de la propiedad Text de un TextBox puede depender de un origen de datos enlazado. Cuando el valor de la propiedad enlazada cambia, el valor de la propiedad Text cambia.

  • El valor de la propiedad Opacity de una Label puede depender de un guión gráfico de animación, en el escenario común en el que configuró un elemento de IU para que aparezca o desaparezca en respuesta a algún evento.

  • El valor de todo tipo de propiedades en cualquier elemento de la interfaz de usuario puede depender del estilo que le hayas aplicado.

El concepto central detrás de la dependencia es que lo que depende debe obtener el valor de la propiedad de lo que depende. Es por esto que una propiedad de dependencia se implementa como una propiedad CLR cuyo captador llama a un método.

Cuando el TextBox , o la cosa que lo está representando, necesita saber cuál es su FontFamily , el getter de FontFamily llama al método GetValue . Ese método encuentra el valor del contenedor, la animación, el enlace o lo que sea.

Hay mucha complejidad en ese método. Si el valor heredado, por ejemplo, funciona de una manera que es bastante análoga a cómo WPF encuentra estilos en un diccionario de recursos: busca en un diccionario local para encontrar el valor, y si no hay una entrada, busca en el diccionario de su padre, y así sucesivamente hasta que encuentre un valor o llegue a la parte superior de la jerarquía, en cuyo caso utiliza un valor predeterminado.

Si observa la implementación de las propiedades de dependencia, eso es lo que encontrará. Un objeto de dependencia tiene un diccionario que puede o no contener una entrada para una propiedad determinada. El método GetValue obtiene valores de ese diccionario (que es cómo los objetos con propiedades de dependencia pueden tener valores locales que anulan lo que heredan), y si no encuentra el valor, utiliza la información sobre la propiedad para averiguar donde debe mirar.

Dado que esa metainformación es la misma para todos los objetos de la clase (es decir, TextBox.Text funciona de la misma manera para todos los TextBox ), el diccionario en el que está almacenado es una propiedad estática de la clase.

Así que cuando veas código como este:

static Button() { // Register the property Button.IsDefaultProperty = DependencyProperty.Register("IsDefault", typeof(bool), typeof(Button), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsDefaultChanged))); }

lo que está sucediendo es que la metainformación que define la propiedad IsDefault en todos los objetos Button se está agregando a ese diccionario. Y cuando veas esto:

public bool IsDefault { get { return (bool)GetValue(Button.IsDefaultProperty); } set { SetValue(Button.IsDefaultProperty, value); } }

lo que está viendo es el método getter que busca el valor de la propiedad (desde el diccionario local, el objeto principal, o lo que sea) en función de esa metainformación.

¿Recuerda cómo dije que el primer lugar en el que el ordenador busca el valor de una propiedad es el diccionario local del objeto? El método SetValue en el SetValue es cómo esa entrada se agrega al diccionario (si alguna vez se llama, solo lo será si está anulando la dependencia al establecer explícitamente la propiedad, es decir, "Quiero que este TextBox muestre el texto en Consolas independientemente de lo que utilicen los otros controles en la ventana ".

Un beneficio muy importante que obtenemos de este tipo de sistema aparentemente complejo es que las propiedades de dependencia de los objetos solo consumen memoria si están configuradas. Si creo 10,000 controles TextBox y los agrego a una Window , ninguno de ellos contiene una referencia a un objeto FontFamily . Son 10.000 referencias de objetos para las que no estoy asignando memoria y que el recolector de basura no está revisando. De hecho, si un TextBox tiene 100 propiedades de dependencia (y las tiene, casi todas), cada vez que crea un TextBox , son 100 campos de respaldo para los que no está asignando memoria. Las propiedades de dependencia solo consumen memoria si las establece explícitamente. Dado que la gran mayoría de las propiedades en los objetos de la interfaz de usuario nunca se establecen explícitamente, estos son ahorros fantásticos.


Otras personas han proporcionado explicaciones de las propiedades de dependencia. Trataré de proporcionar algún contexto en torno a su diseño. (Me ayudó a comprender por qué estas creaciones extrañas llamadas propiedades de dependencia existen en primer lugar). Hubo algunas razones por las que los diseñadores de WPF agregaron propiedades de dependencia en lugar de usar las propiedades normales ...

  1. Poder agregar un valor para una propiedad que no es aplicable al elemento actual, pero es aplicable a sus hijos. Por ejemplo, establecer una fuente en un contenedor y hacer que caiga en cascada a cualquier elemento de texto contenido.
  2. El costo en términos de tamaño para las propiedades no utilizadas. Tomando el ejemplo de fuente anterior ... En una página bien diseñada, solo algunos elementos tendrán su fuente modificada, probablemente algunos contenedores de nivel superior. Si almacenamos la Fuente como una propiedad de C # regular, cada objeto necesitaría un puntero de 32/64 bits a un objeto de fuente con la mayoría de ellos nulos o con un valor predeterminado. Amplíe esto por el número de propiedades XAML y el número típico de elementos en una página y terminará requiriendo una gran cantidad de espacio para almacenar nada o valores predeterminados. Compare esto con las propiedades de dependencia donde los valores solo ocupan espacio si están configurados. (No he visto la implementación interna, pero me imagino que GetValue (propName) y SetValue (propName) almacenan los valores en algún tipo de hashtable por objeto / por propiedad).

Sería bueno si Microsoft proporcionara una sintaxis más agradable para crear nuevas propiedades de dependencia ocultando el código repetitivo con la magia del compilador, como lo hacen para los iteradores. Tal vez en C # 6 ... :)


Para agregar a lo que ya se ha cubierto en otras respuestas:

Conceptualmente, en su núcleo, las propiedades de dependencia son un sistema para permitir que las consultas obtengan un valor basado en una lista de diferentes fuentes en lugar de devolver un solo valor almacenado. Hay muchas ramificaciones a esto, como se indica en muchas de las otras respuestas, pero lo que realmente sucede se traduce en algo que se comporta de esta manera cuando se obtiene un valor (por supuesto, se simplifica enormemente):

private string _coerced; private string _animated; private string _local; private string _triggered; private string _styled; private string _inherited; private string _default; public string MyDP { get { return _coerced ?? _animated ?? _local ?? _triggered ?? _styled ?? _inherited ?? _default; } }


Vea el Resumen de propiedades de dependencia en MSDN (o la versión de Silverlight ).

(Silverlight / WPF) proporciona un conjunto de servicios que se pueden usar para ampliar la funcionalidad de una propiedad CLR. En conjunto, estos servicios generalmente se conocen como el sistema de propiedad (Silverlight / WPF). Una propiedad que está respaldada por el sistema de propiedades (Silverlight / WPF) se conoce como propiedad de dependencia.

Para las diferencias entre los sistemas de propiedad de Silverlight y WPF, vea here .

Un par de razones por las que el sistema de propiedades de dependencia y la conexión de una propiedad con el sistema de tipo Silverlight / WPF son importantes son las siguientes (vea here para obtener explicaciones más detalladas):

  • Permite que una propiedad se pueda configurar en un estilo
  • Permite que una propiedad soporte el enlace de datos
  • Permite que una propiedad sea animable.
  • Permite que las propiedades de un control personalizado reciban soporte del diseñador en Visual Studio

Tenga en cuenta que una propiedad de dependencia suele estar respaldada por una propiedad CLR, lo que significa que puede interactuar con ella en el código de la misma manera que lo haría con una propiedad CLR.


WPF está diseñado alrededor de una arquitectura basada en propiedades y requiere un sistema de propiedades muy potente que admita:

  1. Varios proveedores por su valor, es decir, su valor puede ser cambiado en el tiempo de ejecución por varios proveedores como activadores, estilos, animación, temas, etc. (Precedencia de valor de propiedad de dependencia)
  2. XAML (soporte de expresiones).
  3. Memoria eficiente (su naturaleza estática).
  4. Cambiar notificaciones
  5. Herencia del valor de la propiedad (Propiedades adjuntas).

Artículos que he encontrado muy útiles.

Descripción general de las propiedades de dependencia en WPF: http://joshsmithonwpf.wordpress.com/2007/06/22/overview-of-dependency-properties-in-wpf/

Propiedades de dependencia interna: http://www.i-programmer.info/programming/wpf-workings/443-inside-dependency-properties-.html

WPF: La naturaleza estática de las propiedades de dependencia: http://dotnetslackers.com/Debugger/re-126399_WPF_The_Static_Nature_of_Dependency_Properties.aspx