Reverse ICommands for MVVM

Posted by Rishi on 07-Jan-10 5:13 AM - Comments (11)

One of the problems with MVVM designs is the inability of the ViewModel to singularly effect change(s) within the View; yes, you can use data-changes through data-binding as a crude-bludgeon, but I'd rather have the right tools for the right job. And that is where Reverse ICommands come in, they allow you to execute an ICommand in your ViewModel and have it trigger a set of specified action(s) in the View - the reverse taxonomy speaks to the fact that reverse ICommands targets your View rather than the ViewModel.

AvatarView the sample application here and the source code is also available at Codeplex.

Design: Extends ICommand

In working terms reverse commands are ICommands that acknowledge when they execute - the acknowledgement gives us the ability to respond to them from within the View. Implementation wise, see the IReverseCommand interface, we only add a CommandExecuted event to the ICommand definition.

IReverseCommand

The other part to reverse commands is the ReverseCommandTrigger behavior, to which we can bind our reverse command and associate one or more Trigger Actions to invoke when the associated command is executed. For example, in the Silverlight Console Project the Console definition has a "Beep" method to which we have to make a beeping sound (obviously) - however, the beeping sound playing control lies in our View and we have to trigger it from our ViewModel. So using reverse commands, first in our ViewModel we declare the reverse command property, initialize it to do nothing in our ViewModel (though you can have it do something else), and execute it when asked to beep (the OnBeep method), have a look:

   1: // we define our reverse command as a property in our ViewModel
   2: public IReverseCommand BeepReverseCommand { get; private set; }
   3:  
   4: // and we set it up like this in our ViewModel
   5: BeepReverseCommand = new ActionCommand(() => { });
   6:  
   7: // we handle Beep call request in our ViewModel and Execute the reverse command
   8: protected override void OnBeep() {
   9:     BeepReverseCommand.Execute();
  10: }

Then in our View, the XAML features the Media Element control and a reverse command Trigger which plays the media:

   1: <!-- We define the sound playing Media Element -->
   2: <MediaElement x:Name="beepAudioMedia"
   3:     Source="/Resources/beep.wma" Volume="1" AutoPlay="False"/>
   4:  
   5: <!-- And we set up Reverse Command Trigger to play the media -->
   6: <nTriggers:ReverseCommandTrigger ReverseCommandBinding="{Binding BeepReverseCommand}">
   7:     <Behaviors:PlayMediaElementAction TargetName="beepAudioMedia"/>
   8: </nTriggers:ReverseCommandTrigger>

As you can see, the workflow of reverse commands is very similar to regular ICommands, except we reverse the receiver/sender roles - the ViewModel here explicitly triggers the Command by calling execute, and the View hooks up Actions to go with the execution of the Command. Also note, all the ICommand implementations in nRoute are reversible because they all implement IReverseCommand - so you can use them as regular and/or reversed commands.

Usage: An Example

The attached sample application is really very simple, it basically has three screens and we control the flow and interaction between them from our ViewModel using ICommands and IReverseCommands. The three screens are realized as Visual States on the View and, as shown below, the Home Screen helps get a user's response to a question, the Trailer Screen shows a movie trailer and the Message Screen self-descriptively shows a message.

 SampleAppViewViewModel

Within our ViewModel, the Home command navigates to the Home Screen, the PlayPause command toggles the pause-state of the trailer, the Response command gets the user's response from the Home Screen. The reverse commands help navigate between the screens by changing the Visual State of the View, and the play/pause reverse commands do as they suggest. The idea here is to show how from within the ViewModel we can, without direct dependencies, control the View - like when we navigate away from the Trailer Screen we pause the movie and when we enter into the Trailer Screen we resume the movie all from the ViewModel. Even the playing state of the trailer is kept within the ViewModel, similarly when we get the initial question's response the ViewModel decides which screen to navigate to, and if appropriate which message to show. All this builds on the separation of concerns principle, and though the functionality here is petty, the application of ICommands and IReverseCommands helps us manage the View-ViewModel interaction in both directions.

Summary: ICommands Reversed

ReverseCommandsModel

Per the principles of MVVM, in SL, we have two primary ways of communication between the View and the ViewModel - one, data-changes signifiers that rely on data-binding, and two, ICommands based invocation of actions from the View. Data-changes as a mechanism for inter-communication works for some cases, but in other cases it is too implicit and imprecise, and this is where ICommands weigh in - they are good for explicit, loosely-coupled, and strongly-typed invoking of actions. However ICommands are one-way creatures designed to be invoked from the View, and handled within the ViewModel.

On the other end, invoking of actions from the ViewModel-to-View is the functional gap that IReverseCommands fulfill, and just like ICommands they are explicit, precise and strongly-typed. Further, as with ICommands you also get ICommands-associated functionality like can-execute checks, enabling-disabling of ICommands, and explicitly defining of dependencies like in nRoute. Now, technically there might be many ways to achieve what reverse commands do but for me the fact that here we have a loosely-coupled setup which makes use of the binding infrastructure in SL and extends one the primary communication mechanism to work in reverse is a handsomely meriting solution.

You can view the Sample App here,
you can download the Sample App source-code here,
and read about the rich support for ICommands in nRoute here.

Comments

trackback
DotNetKicks.com
on 22-Dec-09 2:23 PM
Reverse ICommands for MVVM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

trackback
DotNetShoutout
on 22-Dec-09 2:26 PM
Reverse ICommands for MVVM

Thank you for submitting this cool story - Trackback from DotNetShoutout

trackback
Sanjeev Agarwal
on 23-Dec-09 3:04 PM
Daily tech links for .net and related technologies - Jan 7-9, 2010

Daily tech links for .net and related technologies - Jan 7-9, 2010 Web Development Announcing FubuMVC

pingback
drakz.com
on 24-Dec-09 4:51 AM
Pingback from drakz.com

Reverse ICommands for MVVM | Drakz News Station

Michael Washington
Michael Washington United States
on 24-Dec-09 12:32 PM
Very well written (also a nice easy to read blog layout). The commanding implementation you have created makes sense to me.

trackback
DarioSantarelli.Blog(
on 24-Dec-09 1:33 PM
nRoute e

nRoute e

trackback
uberVU - social comments
on 26-Dec-09 12:25 AM
Social comments and analytics for this post

This post was mentioned on Twitter by Orktane: Blogged about my favorite new feature in nRoute: Reverse ICommands for MVVM http://bit.ly/6Z9gTk

pingback
stevepietrek.com
on 27-Dec-09 10:10 AM
Pingback from stevepietrek.com

Links (1/10/2010) « Steve Pietrek-Everything SharePoint/Silverlight

Rishi
Rishi
on 11-Jan-10 2:38 AM
@Michael, thanks. In my experience the issue of having the View react to the VM instruction precisely (as in other than through data-changes) has been a sore point and with Reverse Commands we can overcome that limitation. A very simple example of this is having the View perform navigation - by its very nature navigation is a very View-specific task, but one that can be initialized by the VM - and so by using Reverse Commands we can have that specifically declared and executed.

trackback
orktane
on 12-Jan-10 3:27 AM
iPhone Sudoku in Silverlight using MVVM

iPhone Sudoku in Silverlight using MVVM

Kenia Mcgrapth
Kenia Mcgrapth United States
on 10-Mar-10 6:35 AM
I don't agree with everything in this piece of writing, but you do make some very good points. I'm very interested in this subject and I myself do alot of research as well. Either way it was a well thoughtout and nice read so I figured I would leave you a comment. Feel free to check out my website sometime and let me know what you think.

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading