2010-06-25 15 views
18

He estado leyendo acerca de las propiedades de dependencia en varios libros, pero todos tienen algo en común, simplemente nos dicen cómo se implementan (usandoetc.) pero no dicen la forma exacta en que funcionan desde adentro.Dependencia Propiedad WPF

Quiero decir que se implementan como estáticos, pero todavía se aplica a todos los objetos.
El segundo punto de confusión son las propiedades adjuntas.

¿Hay algún tutorial disponible que pueda explicar todos estos conceptos de una manera fácil?

Respuesta

30

Mi modelo mental de cómo funcionan las propiedades de dependencia:

Cualquier DependencyObject clase implementa dos propiedades especiales. Uno, una propiedad estática de la clase, es un diccionario de objetos DependencyProperty. Cada instancia de la clase puede buscar dentro de ese diccionario la metainformación sobre cada DependencyProperty, el nombre de la propiedad, su tipo, las devoluciones de llamada a las que se debe llamar cuando se obtiene y configura, cómo participa en la herencia de la propiedad, etc. Cuando registra una propiedad de dependencia, está agregando una entrada a este diccionario.

La otra propiedad es una propiedad de instancia: se trata de un diccionario, introducido por DependencyProperty, que contiene el valor local de cada DependencyProperty, si se ha establecido.

Los métodos SetValue y GetValue que implementa en el setter y getter de la propiedad CLR son básicamente una evaluación perezosa con esteroides. En lugar de almacenar y recuperar el valor de la propiedad en un campo de respaldo, almacenan y recuperan el valor de la propiedad en el diccionario de valores.

La magia de las propiedades de dependencia está en lo que GetValue y realmente hacen.

GetValue busca el valor de la propiedad en el diccionario de valores del objeto. Si no lo encuentra, llama al GetValue en el elemento padre, para obtener lo que el elemento padre cree que es el valor. Por ejemplo, cuando crea un TextBox en un Window, cualquier cosa que mire el TextBoxFontFamily está llamando al GetValue. A menos que haya configurado explícitamente la fuente, no hay ninguna entrada en su diccionario para esa propiedad. Entonces GetValue pregunta al elemento padre por el valor.El elemento padre puede o no tener FontFamily establecer; si no, es llame al GetValue para devolver el valor desde su padre. Y así sucesivamente, hasta que se alcanza el objeto Window y se encuentra el valor real FontFamily.

Si configura FontFamily en el TextBox, SetValue almacena el valor en el diccionario de valores. La próxima vez que algo necesite obtener el valor de FontFamily para ese TextBox, GetValue encuentra el valor en el diccionario y lo devuelve, por lo que no necesita preguntar al elemento padre.

Si establece FontFamily en el Window, SetValue no sólo actualiza el valor en el diccionario de valor Window 's, se dispara un evento de cambio de propiedad de que todo depende de la propiedad oye. (Es por eso que se llaman propiedades de dependencia, recuerde). Y si lo que depende de la propiedad es en sí mismo una propiedad de dependencia, activa su propia propiedad: cambia los eventos. Así es como cambiando el FontFamily en el Window se cambia la fuente de cada control en la ventana y también se le pide a WPF que vuelva a procesar los controles que han cambiado.

Las propiedades adjuntas funcionan con el mismo tipo de enfoque. Cualquier objeto que pueda tener propiedades adjuntas tiene un diccionario en el que están almacenados los valores de las propiedades adjuntas. Cuando configura Grid.Column en un CheckBox en XAML, solo está agregando una entrada al diccionario CheckBox. Cuando el Grid necesita saber en qué columna está el CheckBox, se ve el valor de ese diccionario. Cuando establece Grid.IsSharedSizeScope en True en un objeto, el diccionario de ese objeto contendrá una nueva propiedad, un diccionario que contiene anchuras/alturas para cada SharedSizeKey.

Debo enfatizar que este es mi modelo mental. No me senté con Reflector y miré la implementación real de Register, GetValue y SetValue para ver cómo funcionan realmente. Puedo estar equivocado sobre los detalles. Pero es un modelo que predice con precisión cómo se comporta esto, por lo que es lo suficientemente bueno.

El concepto de almacenar valores de propiedad en diccionarios es bastante extraño para los programadores de C#. Aunque es un viejo sombrero para los programadores de Python. En Python, todas las propiedades de clase -todos los objetos, de hecho- se almacenan en diccionarios, de modo que puede obtener su valor a través de los descriptores de propiedades o simplemente buscándolos. Las propiedades de dependencia y las propiedades adjuntas son solo otra forma en que .NET, después de haber robado todo lo que Java tenía que valía la pena robar, ahora está saqueando Python. (O de donde sea que Python los haya saqueado). Aprender Python me ha convertido en un programador de C# mucho mejor; Lo recomiendo a cualquier desarrollador de C# que aún no lo haya hecho.

+0

Robert, muchísimas gracias por esa maravillosa explicación. Ahora podía imaginarme cómo funcionan. No pude entender las propiedades adjuntas correctamente. He aquí lo que entendí: la casilla de verificación tiene un diccionario codificado por una propiedad estática. Ese diccionario puede tener valores codificados para todas las propiedades que tiene el CheckBox. Pero también puede contener otros valores codificados por las propiedades estáticas (Grid.Column) de otros objetos (Grid). Cuando el Grid quiere saber sobre su ubicación, busca una entrada introducida por Grid .Column y Grid.Row y lo utiliza. Así que podemos agregar una entrada para Grid.Column incluso cuando no está dentro de una Grid. –

+0

Robert, ¿estoy en lo cierto? –

+3

Me parece correcto, aunque "Ese diccionario puede tener valores codificados para todas las propiedades que el CheckBox tiene" debería decir "propiedades de dependencia". También debo señalar que cuando escribí la publicación anterior, estaba bajo el error de que las propiedades adjuntas eran un mecanismo como las propiedades de dependencia; de hecho, las propiedades adjuntas * son * propiedades de dependencia. –

6

Aquí es un tutorial sobre las propiedades de dependencia http://www.wpftutorial.net/DependencyProperties.html que explica un poco sobre cómo funcionan.

La breve explicación de por qué el objeto DependencyProperty está en un campo estático es que representa la descripción de la propiedad, no el valor de la propiedad. Cada DependencyObject tiene una asignación de los objetos DependencyProperty a sus valores.

Esta es también la forma en que funcionan las propiedades adjuntas. Como cada DependencyObject almacena una asignación desde cualquier DependencyProperty a un valor, cualquier tipo puede crear una DependencyProperty nueva y establecerla en cualquier DependencyObject existente.

0

Puede ver a continuación un ejemplo muy básico de dependency property que crea un custom control text box en el que el espacio no estará permitido significa que el usuario no puede escribir espacio en el cuadro de texto.

1) Crear una clase con el nombre de ValidatedTextBox y escribir el siguiente código en el archivo de clase:

public class ValidatedTextBox : TextBox 
{ 
    public ValidatedTextBox() 
    { 
    } 

    public static readonly DependencyProperty IsSpaceAllowedProperty = 
     DependencyProperty.Register("IsSpaceAllowed", typeof(bool), typeof(ValidatedTextBox)); 

    public bool IsSpaceAllowed 
    { 
     get { return (bool)base.GetValue(IsSpaceAllowedProperty); } 
     set { base.SetValue(IsSpaceAllowedProperty, value); } 
    } 

    protected override void OnPreviewKeyDown(KeyEventArgs e) 
    { 
     base.OnPreviewKeyDown(e); 
     if (!IsSpaceAllowed && (e.Key == Key.Space)) 
     { 
      e.Handled = true; 
     } 
    } 
} 

2) Ahora utilice el control anterior en su archivo .XAML

a) Añadir espacio de nombres del cuadro de texto control personalizado, como a continuación:

xmlns:CustomControls="clr-namespace: ValidatedTextBox;assembly= ValidatedTextBox " 

b) Ahora, utilice cuadro de texto control personalizado, como a continuación:

<CustomControls:ValidatedTextBox IsSpaceAllowed="False" x:Name="MyTextBox" /> 

Se va a crear un cuadro de texto control personalizado que no permita el espacio. Por lo tanto, la propiedad Básicamente Dependencia permite agregar características, ampliar la característica de cualquier control.

Cuestiones relacionadas