Les AttachedProperty
Ce type de propriété permet d'enrichir les propriétés existantes d'un objet. Ce sont des propriétés qui n'ont pas forcément de sens au niveau du contrôle lui-même, mais qui en ont au vu d'un contexte externe. Les AttachedProperty les plus connues sont Canvas.Left, Canvas.Top, Grid.Column et Grid.Row. Vous remarquerez que la propriété colonne n'a aucun sens sur un contrôle en dehors du contexte de la grille.
Ces AttachedProperty nous permettent d'étendre le comportement de nos contrôles. Nikhilk nous donne un exemple d'implémentation d'un framework de comportement sur son blog.
Le Command pattern
Ce pattern a pour but de séparer le comportement de la partie IHM. L'idée est de ne plus s'attacher directement aux événements des contrôles et de passer par un objet Command qui va faire la liaison entre le comportement et la saisie des utilisateurs.
Vous trouverez une bonne description du pattern Command en WPF sur le site de microsoft. Cette séparation permet de pouvoir déclencher l'action depuis l'IHM mais aussi depuis d'autres classes métiers.
Le code
La classe centrale est CommandService. Elle défini les AttachedProperty, c'est elle qui devra être référencée dans le xaml pour relier un contrôle à une commande.
<UserControl xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sle="clr-namespace:SLExtensions.Input;assembly=SLExtensions"
...
<Button Content="Open" Width="50" Height="30"
sle:CommandService.Command="Open"
sle:CommandService.CommandParameter="{Binding OpenFileInfo, Source={StaticResource controller}}" />
...
</UserControl>
Dans cet exemple, le bouton "Open" est bindé à la commande Open. On passe en paramètre à la commande un object OpenFileInfo qui est stocké sur le contrôleur de la page. Il sert à passer les paramètres d'exécution de la commande.
Du coté métier, le contrôleur de la page s'attache à l'événement Executed de la commande
...
TestCommands.OpenCommand.Executed += new ExecutedEventHandler(OpenCommand_Executed);
...
void OpenCommand_Executed(object sender, ExecutedEventArgs e)
{
OpenFileDialogInfo info = e.Parameter as OpenFileDialogInfo;
if (info != null)
{
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.EnableMultipleSelection = info.EnableMultipleSelection;
ofd.Filter = info.Filter;
ofd.ShowDialog();
}
}
}