Kona – Commands

January 18, 2013

no comments

The first thing I will cover in the series about Kona is the good old DelegateCommand class, that all of the Prism veterans learned to respect. But first, a quick overview for those of you who never worked with commands before.

Why do we need commands for?

One of the corner stones of MVVM is clear separation of the view from the view model. Those two components should be as loosely coupled as possible and interact only by using binding. To accomplish this separation, the view model exposes it’s data with properties, and the view presents and manipulates that data by using the Binding markup extension. At runtime, the Binding expressions are resolved by inspecting the DataContext property of the control, which holds a reference to the view model (how the view model ends up being referenced in the control’s DataContext property is another issue which is solved elegantly by Kona. I will cover this in another post).

The following example shows a page with a TextBlock control with its Text property bounded to the view model’s CustomerName property:

   1: <Page

   2:     x:Class="KonaSample.MainPage"

   3:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   4:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

   5:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   6:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   7:     xmlns:Infrastructure="using:Kona.Infrastructure" 

   8:     Infrastructure:ViewModelLocator.AutoWireViewModel="True"

   9:     mc:Ignorable="d">

  10:  

  11:     <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

  12:         <TextBlock Text="{Binding CustomerName}"

  13:                    VerticalAlignment="Center"

  14:                    HorizontalAlignment="Center"

  15:                    FontSize="40"/>

  16:     </Grid>

  17: </Page>

And the corresponding view model:

   1: using Kona.Infrastructure;

   2:  

   3: namespace KonaSample

   4: {

   5:     public class MainPageViewModel : ViewModel

   6:     {

   7:         private string m_customerName;

   8:  

   9:         public MainPageViewModel()

  10:         {

  11:             m_customerName = "Moshe";

  12:         }

  13:  

  14:         public string CustomerName

  15:         {

  16:             get { return m_customerName; }

  17:             set { SetProperty(ref m_customerName, value); }

  18:         }

  19:     }

  20: }

This is the entire code. All the wiring is automatically done by the infrastructure. Note that the view and the view model does not know each other at all.

Binding supports a broader set of features. For example, the bounded element can be automatically updated given that the view model raises a specific event when the property changes (This also will be covered in another post).

Interaction with properties is only one side of the equation. What can you do if you need to invoke a method on the view model after the user performs an action in the view, for example, clicks a button? This is where you will use commands.

The ICommand interface

In XAML, each control that supports command invocation, such as ButtonBase and its derivatives, has the following additional dependency properties:

  • Command: A reference to an ICommand object to invoke.
  • CommandParameter: An optional parameter to pass to the ICommand object upon invocation.

In order to invoke a method on the view model when the user clicks a button, you need to create a new class, derived from the ICommand interface, create an instance of that class in your view model, expose it via a property, and then bind the Command property of the button to that property. The button will be enabled or disabled based on the command’s CanExecute method, and when the button will be clicked, the command’s Execute method will be invoked.

The following example shows a page with a Button control with its Command property bounded to the view model’s CreateCommand property:

   1: <Page

   2:     x:Class="KonaSample.MainPage"

   3:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   4:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

   5:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   6:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   7:     xmlns:Infrastructure="using:Kona.Infrastructure" 

   8:     Infrastructure:ViewModelLocator.AutoWireViewModel="True"

   9:     mc:Ignorable="d">

  10:  

  11:     <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

  12:         <Button Command="{Binding CreateCommand}"

  13:                 VerticalAlignment="Center"

  14:                 HorizontalAlignment="Center"

  15:                 Content="Create"/>

  16:     </Grid>

  17: </Page>

And the corresponding view model:

   1: using System;

   2: using System.Windows.Input;

   3: using Kona.Infrastructure;

   4:  

   5: namespace KonaSample

   6: {

   7:     public class MainPageViewModel : ViewModel

   8:     {

   9:         public ICommand CreateCommand { get; private set; }

  10:  

  11:         public MainPageViewModel()

  12:         {

  13:             CreateCommand = new CreateCommand();

  14:         }

  15:     }

  16:  

  17:     public class CreateCommand : ICommand

  18:     {

  19:         public bool CanExecute(object parameter)

  20:         {

  21:             // This command can always be executed

  22:             return true;

  23:         }

  24:  

  25:         public void Execute(object parameter)

  26:         {

  27:             // Do some operation...

  28:         }

  29:  

  30:         public event EventHandler CanExecuteChanged;

  31:     }

  32: }

Implementing the ICommand interface for each and every command in your view model is redundant, tedious and time consuming.

DelegateCommand and DelegateCommand<T>

These two simple classes, available in Kona, will save you a lot of time when you need to implement more than a few commands. The concept behind them is pretty simple. Instead of creating a new class for each command, just create an instance of the DelegateCommand class and pass it the Execute and CanExecute methods as delegates. Use the non-generic class for commands that do not receive parameter, and the generic class for commands that receive parameter. The parameter will be typed, unlike the nasty object parameter in the ICommand interface.

The following example shows the above view model, refactored to use a DelegateCommand:

   1: using System.Windows.Input;

   2: using Kona.Infrastructure;

   3:  

   4: namespace KonaSample

   5: {

   6:     public class MainPageViewModel : ViewModel

   7:     {

   8:         public ICommand CreateCommand { get; private set; }

   9:  

  10:         public MainPageViewModel()

  11:         {

  12:             CreateCommand = new DelegateCommand(OnCreateExecuted);

  13:         }

  14:  

  15:         private void OnCreateExecuted()

  16:         {

  17:             // Do some operation...

  18:         }

  19:     }

  20: }

Notice that you do not have to implement the CanExecute method for commands that can always be executed.

As you can see, using the DelegateCommand class is more elegant than re-implementing the ICommand interface. Next time I will walk you through Kona’s ViewModel class, and the ViewModelLocator class, which is responsible for the magic that automatically wires the views and the view models.

cross-posted from http://www.programmingtidbits.com/post/2013/01/18/Kona-Commands.aspx

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*