Warning : This page has been marked as an archive because the author consider that its content is no longer relevant.

Dans un article précédent, je vous avais parlé de l’utilisation des commandes avec nRoute. A titre de rappel, les commandes permettent à la vue d’envoyer un message au view model pour qu’il exécute une action particulière. Mais comment faire dès lors que, depuis le view model, nous avons besoin d’envoyer un message à la vue pour, par exemple, changer l’état visuel d’un contrôle avec son VisualStateManager ?

Les commandes inversées alias ReverseCommands ont été créées précisément pour remplir cette fonction.

Contexte

Afin d’illustrer cet article, on va d’abord créer une application Silverlight classique. Voici le Xaml de la MainPage :

<UserControl x:Class="nRoute_ReverseCommands.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:n="http://nRoute/schemas/2010/xaml">

    <i:Interaction.Behaviors>
        <n:BridgeViewModelBehavior />
    </i:Interaction.Behaviors>

    <Grid x:Name="LayoutRoot" Background="White">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="VisualStateGroup">
                <VisualState x:Name="RedState">
                    <Storyboard>
                        <ColorAnimation Duration="0" To="Red"
                                        Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                        Storyboard.TargetName="rectangle" />
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="BlueState">
                    <Storyboard>
                        <ColorAnimation Duration="0" To="Blue"
                                        Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                        Storyboard.TargetName="rectangle" />
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Rectangle x:Name="rectangle" Width="50" Height="50" Fill="Transparent" />
    </Grid>
</UserControl>

La grille possède deux états visuels, l’un qui peindra le rectangle en bleu et l’autre qui le peindra en rouge.

Le but de l’exemple va être de changer la couleur du rectangle toute les secondes grâce à ses états visuels et à l’utilisation de commandes inversées.

Voici le view model de départ :

public class MainPageViewModel : ViewModelBase
{
    private bool _ok;
    private readonly DispatcherTimer _timer;

    public MainPageViewModel()
    {
        _timer = new DispatcherTimer();
        _timer.Interval = TimeSpan.FromSeconds(1);
        _timer.Tick += (s, a) => OnTimerTick();
        _timer.Start();
    }

    private void OnTimerTick()
    {
        // Changer l'état visuel
        _ok = !_ok;
    }
}

Création et initialisation des commandes

Dans le code ci-dessus, on initialise un timer qui appelle la méthode OnTimerTick toutes les secondes. Dans cette méthode nous devons donner l’ordre à la vue de changer d’état visuel. Pour ce faire nous allons créer deux commandes inversées :

private readonly IReverseCommand _okCommand;
private readonly IReverseCommand _koCommand;

Et ne pas oublier de les initialiser avec une action vide dans le constructeur du view model :

_okCommand = new ActionCommand(() => { });
_koCommand = new ActionCommand(() => { });

Ici, on peut voir que les ActionCommand qu’on a déjà utilisé auparavant implémentent IReverseCommand. Cependant, l’initialisation d’une commande inversée n’a rien de différent de celle d’une commande normale. Ce qui diffère, c’est son utilisation : on a initialisé la commande avec une action vide car on n’a pas d’actions en provenance de la vue à traiter.

Si on regarde la définition de IReverseCommand, on voit qu’elle n’expose qu’un seul évènement nommé CommandExecuted. Nous verrons en quoi cela permettra d’exécuter une action dans la vue un peu plus loin.

Maintenant que nos commandes sont initialisées, on va pouvoir les utiliser. Pour cela, on va modifier le corps de la méthode OnTimerTick afin d’exécuter les commandes inversées Ok et Ko une fois sur deux alternativement :

private void OnTimerTick()
{
    if (_ok)
        _okCommand.Execute(null);
    else
        _koCommand.Execute(null);
    _ok = !_ok;
}

On doit aussi l’exposer à la vue, on rajoute donc deux propriétés :

public ICommand OkCommand { get { return _okCommand; } }
public ICommand KoCommand { get { return _koCommand; } }

Liaison des commandes inversées à la vue

Le view model est maintenant terminé et il est temps de retourner dans la vue pour utiliser les commandes inversées exposées. nRoute fournit à cette fin un trigger qui va s’abonner à l’évènement CommandExecuted exposé par l’interface IReverseCommand et nous permettre d’exécuter une action dans la vue. Ce trigger est le ReverseCommandTrigger et on va voir tout de suite comment il s’utilise. Dans le Xaml de la MainPage, on va rajouter des triggers sous la déclaration des états visuels (balise VisualStateManager.VisualStateGroups).

<i:Interaction.Triggers>
    <n:ReverseCommandTrigger ReverseCommand="{Binding OkCommand}">
        <ei:GoToStateAction StateName="BlueState" />
    </n:ReverseCommandTrigger>
    <n:ReverseCommandTrigger ReverseCommand="{Binding KoCommand}">
        <ei:GoToStateAction StateName="RedState" />
    </n:ReverseCommandTrigger>
</i:Interaction.Triggers>

La déclaration est assez claire et parle d’elle même. Lorsque la commande OkCommand est invoquée, on charge l’état visuel “BlueState”. Lorsque la commande KoCommand est invoquée, on charge l’état visuel “RedState”. Au lieu de changer l’état visuel on aurait pu faire d’autres actions comme lancer un storyboard, effectuer une navigation etc… Le choix en revient désormais à la vue.

Maintenant, si on lance l’application on a un joli rectangle qui change de couleur toutes les secondes.

Vous pourrez trouver le code d’exemple de cet article sur mon skydrive.

A vous de jouer maintenant !

Comments