nRoute - Reverse commands

3 minutes read

Introduction

In a previous article, I had talked about using commands with nRoute. Just to remind you, commands allow the view to send messages to the view model which will in turn execute a particular action. But what if, from the view model, we need to send a message to the view to change, for example, the visual state of a control with its VisualStateManager?

ReverseCommands has been created precisely for this purpose.

Context

In order to illustrate this article, we will first create a simple Silverlight application. Here is the Xaml code from the 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>

The grid has two visual states : one will paint the rectangle in blue, the other in red.

The goal of this example is to change the color of the rectangle every second using its visual states and reverse commands.

Here is the starting view model :

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;
    }
}

Commands creation and initialization

In the above code, we initialize a timer which calls the OnTimerTick method every second. In this method, we have to order the view to change the visual state. For this, we will create two reverse commands :

private readonly IReverseCommand _okCommand;
private readonly IReverseCommand _koCommand;

And not forget to initialize them with an empty action in the constructor of the view model :

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

We can see here that the ActionCommands that we have previously used implement IReverseCommand. Howerer, the initialization of a reverse command has nothing different from one of a normal command. What changes is its use : we initialized the command with an empty action because we don’t have actions from the view to treat.

If we look at the definition of IReverseCommand, we can see that it exposes only one event named CommandExecuted. We will see how this will permit us to execute an action in the view a little further.

Now that our commands are initialized, we will be able to use them. We will modify the corpse of the OnTimerTick method in order to execute the reverse commands Ok and Ko alternately :

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

We must also expose it to the view, so we add two properties :

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

Linking reverse commands to the view

We finished the view model and it is now time to return to the view so we can use the exposed reverse commands. For this, nRoute provides a trigger that will subscribes to the CommandExecuted event exposed by the IReverseCommand interface, allowing us to execute the action in the view. This trigger is called ReverseCommandTrigger and we will see now how we can use it.

In the Xaml of the MainPage, we will add triggers under the declaration of the visual states (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>

The declaration is quite clear and speaks for itself. When the OkCommand is invoked, we load the “BlueState” visual state. When it is the KoCommand that is invoked, we load the “RedState” visual state. Instead of changing the visual state, we could have taken other actions like launching a storyboard, navigate, etc. It’s now up to the view to choose.

If we now launch the application, we have a beautiful and lovely rectangle which changes color every second.

You can find the source code of this article on my skydrive.

It’s up to you now !

Updated:

Leave a Comment