Commands
In Part 2 we looked at how we could solve navigation in a managable way.
I did this by the assumption that one view would have one viewmodel, and apparently this caused some disagreements and a great blogpost by my friend and former colleague (and now colleague again), Olav Nybø. :)
I value Olavs opinions greatly, as he is a seasoned developer with alot of experience. I will try to address his points in a later post, but for the purposes of this series, I'll move ahead on my path. Just a quick side-note - The views and opinions in this series are simply one of many approaches, and not necessarily a best practice.. Who knows - maybe I'll realize that I did it all wrong in the end :)
With that - let's move along!
Commands
If you've ever done any Windows Forms or Windows Mobile (<=6.5), you've probably done your share of event handling. That was pretty much the way to link a click on a button to some code behind logic. What's nice about it is that it gives you the ability to doubleclick the control, and you'll be in your event, ready to write code. Aaaand - that's about it.
The downside is that it tightly and neatly couples your view to your code, and after a while it all makes it very messy, not to mention synchronous.
In WPF/Silverlight/WP7 we can utilize the power of Commands. In Part 2, we hooked up the button on the MainPage.xaml to a click-event that navigated to the subpage. Let's see how we can utilize Commands to do the same
DelegateCommand
In order to do this, we'll implement a small helperclass that we'll call DelegateCommand. I got this class from Windowsphonegeek, and it's a great implementation!
public class DelegateCommand : ICommand { Func<object, bool> canExecute; Action<object> executeAction; private readonly string _canExecuteProperty;public DelegateCommand(Action<object> executeAction) : this(executeAction, null) { } public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute) { if (executeAction == null) { throw new ArgumentNullException("executeAction"); } this.executeAction = executeAction; this.canExecute = canExecute; } public bool CanExecute(object parameter) { bool result = true; Func<object, bool> canExecuteHandler = this.canExecute; if (canExecuteHandler != null) { result = canExecuteHandler(parameter); } return result; } public event EventHandler CanExecuteChanged; public void RaiseCanExecuteChanged() { EventHandler handler = this.CanExecuteChanged; if (handler != null) { handler(this, new EventArgs()); } } public void Execute(object parameter) { this.executeAction(parameter); } }
Once we have that in place we can start implementing some code of our own.
Let's skip over to our MainPageViewModel.cs and implement a Command that will navigate us to the SubPage (we'll also remove the code from our MainPage.xaml.cs)
MainPageViewModel.cs
public MainPageViewModel() { Title = "Kick Ass"; NavigateToSubPageCommand = new DelegateCommand(this.NavigateToSubPage); } public string Title { get; private set; } public ICommand NavigateToSubPageCommand { get; private set; } public void NavigateToSubPage(object args) { App.ViewModel.Goto<SubPageViewModel>(); }
In the above code, we create a public property named NavigateToSubPageCommand of type ICommand, and if you noticed, the DelegateCommand implements this interface. This enables us to initialize this to the a DelegateCommand set to execute the public method NavigateToSubPage in the constructor. The NavigateToSubPage utilizes our navigationsetup that we created in Part 2, and I still think it's a pretty neat way of navigating our application :)
Next off, we delete the click eventhandler in our MainPage.xaml.cs, leaving us with nothing but the generated constructor.
In order for this command to be executed we'll have to change the binding in our MainPage.xaml:
<!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Button x:Name="GoToSubpage" Content="Go to subpage" Command="{Binding NavigateToSubPageCommand}" /> </Grid>
As you see, I simply removed the Click-attribute and substituted it with a Command attribute instead, binding it to the NavigateToSubPageCommmand on our MainPageViewModel
If you try to run the application, you'll see the exact same result as before, but now the logic is moved to the ViewModel where it belongs, instead of the evil code behind.
Summing up
So why did we do this again? Well, for starters, we want our application as decoupled as possible. This example was simple, but with the DelegateCommand (or simply the ICommand interface) we can make specific commands executing very specific operations in our application. This makes it extremely easy to manage and change our code without breaking all sort of things. We can also reuse the commands across our application without copy/pasting code from our code-behind file.
Thanks for reading!