Binding et System.Windows.Interactivity

Binding Interactivity

Dans un post précédent, je vous ai parlé du nouveau nom d’espace System.Windows.Interactivity qui introduit les notions de Behavior, ActionTrigger et Action. Les plus téméraires ont dû remarquer que je n’utilisais pas de technique de Binding sur les objets attachés à notre contrôle utilisateur. En fait, la raison est simple, on ne peut pas, enfin de base. En effet, en Silverlight 3, la technologie de Binding n’est utilisable que sur des objets de type FrameworkElement. Je vais vous montrer une astuce pour pouvoir utiliser le Binding sur nos objets attachés a nos contrôles afin de les utiliser avec le pattern MVVM.

L’astuce repose sur le principe des propriétés attachées. Il suffit d’attacher une de ces propriétés à un FrameworkElement pour pouvoir utiliser le Binding avec le contexte de cet élément.

Afin d’y voir plus clair, passons au développement et commençons par créer une classe héritant d’ActionTrigger<T&gt; qui aura pour rôle d’exécuter une commande. Le but sera de créer une classe s’utilisant de cette façon :

1
2
3
4
5
6
7
<TextBox>
    <i:Interaction.Triggers>
        <Input:KeyTrigger Key="Enter" FiredOn="KeyDown">
            <local:ExecuteCommandDataContextAction Command="{Binding HelloWorldCommand}"/>
        </Input:KeyTrigger>
    </i:Interaction.Triggers>
</TextBox>

Le début de notre classe ressemble à cela :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ExecuteCommandDataContextAction : TriggerAction<UIElement>
{
    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof (XXXX), typeof (ExecuteCommandDataContextAction), null);
 
    public XXXX Command
    {
        get { return (XXXX) this.GetValue(CommandProperty); }
        set { this.SetValue(CommandProperty, value); }
    }
 
    protected override void Invoke(object parameter)
    {
    }
}

Vous avez noté que le type de notre propriété Command n’est pas vraiment défini. Je préfère pour l’instant y faire abstraction, ça ne ferait que vous embrouillez.

Maintenant, réfléchissons un peu en ayant en tête les propriétés attachées qui permettent d’utiliser du Binding dans le contexte d’un contrôle choisi. Il suffit d’attacher une propriété attachée à notre AssociatedObject, de l’assigner avec un Binding voulu et d’intercepter le changement de valeur.

Let’s go ! On définit notre propriété attachée en signalant que l’on souhaite intercepter un changement de valeur :

1
2
3
4
5
6
7
8
9
10
private readonly DependencyProperty CommandAttachedProperty;
public ExecuteCommandDataContextAction()
{
    this.CommandAttachedProperty = DependencyProperty.RegisterAttached("CommandAttachedProperty", typeof (ICommand), typeof (ExecuteCommandDataContextAction), new PropertyMetadata(null, new PropertyChangedCallback(this.OnCommandAttachedPropertyChanged)));
}
 
private void OnCommandAttachedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    this._command = e.NewValue as ICommand;
}

Vous remarquez que grâce à ce principe, on arrive à résoudre un Binding dans le contexte de notre AssociatedObject. Nice, non ?
Alors, pour finir, revenons à notre propriété Command, devinez ce qui accepte d’être assigne à un Binding ? Ben un Binding ! Vous avez compris, l’astuce est de définir notre propriété Command avec le type Binding. Grâce à ça, lors de l’attachement de notre ActionTrigger avec la TextBox, il suffit d’assigner un Binding sur CommandAttachedProperty avec la valeur de Command :

1
2
3
4
5
6
protected override void OnAttached()
{
    base.OnAttached();
 
    (this.AssociatedObject as FrameworkElement).SetBinding(this.CommandAttachedProperty, this.Command);
}

Un petit récapitulatif de notre classe :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ExecuteCommandDataContextAction : TriggerAction<UIElement>
{
    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof (Binding), typeof (ExecuteCommandDataContextAction), null);
 
 
    private readonly DependencyProperty CommandAttachedProperty;
    private ICommand _command;
 
    public ExecuteCommandDataContextAction()
    {
        this.CommandAttachedProperty = DependencyProperty.RegisterAttached("CommandAttachedProperty", typeof (ICommand), typeof (ExecuteCommandDataContextAction), new PropertyMetadata(null, new PropertyChangedCallback(this.OnCommandAttachedPropertyChanged)));
    }
 
    public Binding Command
    {
        get { return (Binding) this.GetValue(CommandProperty); }
        set { this.SetValue(CommandProperty, value); }
    }
 
 
    private void OnCommandAttachedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        this._command = e.NewValue as ICommand;
    }
 
    protected override void Invoke(object parameter)
    {
        if(_command.CanExecute(null))
            this._command.Execute(null);
    }
 
    protected override void OnAttached()
    {
        base.OnAttached();
 
        (this.AssociatedObject as FrameworkElement).SetBinding(this.CommandAttachedProperty, this.Command);
    }
}

Voilà, la boucle est bouclée ! Vous remarquerez rapidement que cette implémentation a de nombreuses lacunes, par exemple si nous instancions deux fois notre classe, elle va créer deux fois une propriété attachée avec le même nom ce qui causera quelques soucis. C’est la qu’intervient les recherches que j’effectue avant chaque article pour les faire les plus complets possibles. Lors de mes recherches, j’ai découvert un projet sur Codeplex nommé Expression Blend Samples, vous le trouverez à l’URL suivante : http://expressionblend.codeplex.com/. Ce projet contient différent exemples d’utilisations des Behaviors… Et vous trouverez notamment une classe nommé BindingListener qui permet de faire rapidement ce que l’on a fait dans cet article, comme d’habitude, je vous la laisse découvrir par vous-même et bien entendu n’hésitez pas à me poser des questions et me laisser des commentaires !

Merci à vous de me lire, de me supporter et de me comprendre !

Pour finir, je vous invite à faire un petit tour sur le blog de mon ami SlashEne alias Shortcutman ! Vous trouverez l’adresse sur votre droite (sur votre écran hein ^^).

Publié dans .NET, Développement, Silverlight.

Classé dans , , , , , , , , , , .


0 réponses

Suivez la conversation, abonnez-vous au flux RSS des commentaires..



Un peu de HTML est permis

ou héberger un rétrolien.