Nous avons parlé dans un précédent post du databinding WPF/Silverlight en expliquant qu’est ce que le databinding, les Dependency Property, Attached Property et DataContext. Dans cet article nous allons nous intéresser plus particulièrement aux Dependency Property et aux Attached Property pour voir comment sont-ils implémentés.
Dependency Properties
Pour ce faire, nous allons commencer par créer une Dependency property, nous disposons pour cela du snippet VS, positionnez vous dans le code behind d’un fichier xaml et tapez propdp puis 2 fois sur la touche TAB.
Voici le code créé :
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(MyType), new PropertyMetadata(MyPropertyChanged));
Dans le code créé par défaut par ce snippet, j’ai modifié deux petites partie : le type au quel on rajoute la Dependency Property (MyType) et une nouvelle instance de PropertyMetaData à la quelle on passe en paramètre le délégué qui traite le callback de l’évènement DependencyPropertyChanged (MyPropertyChanged). On s’arrête juste un petit instant sur ce point : On avait dit l’article précédent qu’une Dependency Property embarque des moyens de notification, à l’aide de cette méthode on va pouvoir interagir lorsque la propriété est modifiée. Voici la méthode MyPropertyChanged :
static void MyPropertyChanged(DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
}
Le premier argument est l’instance de la classe dont la propriété a été modifiée. Le deuxième argument est un objet de type DependencyPropertyChangedEventArgs qui nous met à disposition des données précieuses
NewValue : Valeur de la propriété après modification (de type object)
OldValue : Valeur de la propriété avant modification (de type object)
Property : L’instance de la Dependency Property
Dans la déclaration le la Dependency Property, nous distinguons 2 parties :
- Une propriété CLR (MyProperty), nous remarquons les méthodes GetValue et SetValue respectivement utilisées dans le Set et le Get de la propriété. Ces deux méthodes sont définies au niveau de Dependency Object c’est pour cela que la classe qui définit une Dependency Property doit être un Dependency Object. Elles servent à récupérer / mettre à jour la valeur effective de la Dependency Property. La valeur n’est donc pas stockée au niveau de l’objet qui définit la Dependency property.
- Une Dependency Property qui, comme l’indique si bien le commentaire généré, fait office de stockage pour la propriété CLR MyProperty. Intéressons nous maintenant à la méthode statique Register de la classe DependencyProperty. Si on fait un petit Reflector sur WindowsBase.dll –> System.Windows –> Dependency Property on trouve la méthode Register. Et quelques appels de méthodes plus loin on se retrouve dans la méthode RegisterCommon qui nous intéresse. Au début de cette méthode nous retrouvons ces quelques lignes de code :
La classe FromKeyName est instanciée pour avoir la clé Key à partir du nom de la propriété et du type qui définit la Dependency Property, ensuite la clé résultat est utilisée pour voir si cette elle est contenue dans PropertyFromName et si c’est le cas on dit que la propriété existe déjà. Donc ce qu’on peut en tirer pour l’instant c’est que PropertyFromName contient toutes les clés des Dependency Properties. Si on regarde PropertyFromName on s’aperçoit que c’est une Hashtable, nous savons qu’une Hashtable est une collection de pairs clé / valeur. Donc on connait déjà la clé qui est la clé des Dependency property de type FromKeyName, il nous manque uniquement la valeur.
Poursuivons maintenant la lecture de la méthode, pour trouver plus loin le stockage de la Dependency Property à l’aide de cette ligne :
Où dp est la Dependency Property.
Le stockage des Dependency Properties se fait donc tout simplement dans une Hashtable où la clé est de type FromNameKey et la valeur est la Dependency Property.
Attached Properties
Regardons maintenant comment ça se passe pour une Attached Property. Le snippet VS pour créer une Attached Property est propa voici le code généré :
public static int GetTestProperty(DependencyObject obj)
{
return (int)obj.GetValue(TestPropertyProperty);
}
public static void SetTestProperty(DependencyObject obj, int value)
{
obj.SetValue(TestPropertyProperty, value);
}
// Using a DependencyProperty as the backing store for TestProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TestPropertyProperty =
DependencyProperty.RegisterAttached("TestProperty", typeof(int), typeof(Button), new PropertyMetadata(MyPropertyChanged));
Nous remarquons deux différences :
- Le getter / setter sont deux fonctions statiques au lieu d’une propriété dans le cas d’une Dependency Property. C’est grâce à ça qu’on peut bénéficier des Attached Properties sur tous les objets.
- On utilise la méthode RegisterAttached au lieu de Register. En creusant un peu avec Reflector WindowsBase.dll –> System.Windows –> Dependency Property on trouve la méthode RegisterAttached qui appelle une autre méthode appelée RegisterAttached qui appelle elle même la méthode RegisterCommon appelée lors du Register d’une Dependency Property. On retombe donc sur nos pieds!!!
Le stockage d’une Attached Property se fait de la même manière que pour une Dependency Property c’est à dire dans une Hashtable.