5 Simple Steps to Commanding in Silverlight | John Papa

John Papa

Evangelist on the loose

5 Simple Steps to Commanding in Silverlight

...

Implementing ICommand in your Silverlight 4 project only requires a few steps. I have had a dozens of questions about this lately so I decided to share a very simple technique to implement commanding in Silverlight 4.

Step 1 – Implement ICommand

The first step is to implement the ICommand interface with a class that will manage the commanding aspects. There are other options to do this, but here is a simplified yet powerful implementation of ICommand.

The DelegatedCommand class implements ICommand’s CanExecute method, the Execute method, and the CaneExecuteChanged event. This code can be copied and used “as is”.

   1: public class DelegateCommand : ICommand

   2: {

   3:     Func<object, bool> canExecute;

   4:     Action<object> executeAction;

   5:     bool canExecuteCache;

   6:  

   7:     public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute)

   8:     {

   9:         this.executeAction = executeAction;

  10:         this.canExecute = canExecute;

  11:     }

  12:  

  13:     #region ICommand Members

  14:  

  15:     public bool CanExecute(object parameter)

  16:     {

  17:         bool temp = canExecute(parameter);

  18:  

  19:         if (canExecuteCache != temp)

  20:         {

  21:             canExecuteCache = temp;

  22:             if (CanExecuteChanged != null)

  23:             {

  24:                 CanExecuteChanged(this, new EventArgs());

  25:             }

  26:         }

  27:  

  28:         return canExecuteCache;

  29:     }

  30:  

  31:     public event EventHandler CanExecuteChanged;

  32:  

  33:     public void Execute(object parameter)

  34:     {

  35:         executeAction(parameter);

  36:     }

  37:  

  38:     #endregion

  39: }

Step 2 – Define the Command

Add a public property to your ViewModel to represent the ICommand. This property will be bound to your View through a button, generally.

public ICommand LoadProductsCommand { get; set; }

Step 3 – Create the Command

In the constructor of your ViewModel, set the command property you created in step 1.

LoadProductsCommand = new DelegateCommand(LoadProducts, CanLoadProducts);

Step 4 – Create the VM

You must then make sure your ViewModel is accessible in your View. This is can be done in many ways. But for simplicity I am showing the ViewModel created as a static resource in the View’s XAML.

<UserControl.Resources>

    <local:ProductViewModel x:Key="vm"/>

</UserControl.Resources>

Step 5 – Bind the Command

Add a button control and bind the Command property to the command you created in the ViewModel. Then if you need to pass a parameter into the command you can bind the CommandParameter property to an element in the View. I find that I generally do not need to pass a parameter in, but I added this here as an example.

<Button Content="Load" Width="120"

    Command="{Binding LoadProductsCommand}"

    CommandParameter="{Binding ElementName=FilterTextBox, Path=Text}" />

That’s it! 5 simple steps and now you have commanding in your application.

Want More …

I included the key code files in the post, below. No need to dive into them unless you want to grab the code as a starting point.

The complete ProductViewModel code can be seen here:

   1: public class ProductViewModel : ViewModelBase

   2: {

   3:     public ProductViewModel()

   4:     {

   5:         this.Products = new ObservableCollection<Product>();

   6:  

   7:         // Warning: DEMO CODE AHEAD

   8:         // Your ViewModel should not define your data for your Model :-) 

   9:         // Instead, it could make a call to a service to get the data for the Model.

  10:         this.AllProducts = new ObservableCollection<Product>();

  11:         this.AllProducts.Add(new Product { ProductId = 1, ProductName = "Apple" });

  12:         this.AllProducts.Add(new Product { ProductId = 2, ProductName = "Orange" });

  13:         this.AllProducts.Add(new Product { ProductId = 3, ProductName = "Banana" });

  14:         this.AllProducts.Add(new Product { ProductId = 4, ProductName = "Pear" });

  15:         this.AllProducts.Add(new Product { ProductId = 5, ProductName = "Grape" });

  16:         this.AllProducts.Add(new Product { ProductId = 6, ProductName = "Grapefruit" });

  17:         this.AllProducts.Add(new Product { ProductId = 7, ProductName = "Strawberry" });

  18:         this.AllProducts.Add(new Product { ProductId = 8, ProductName = "Melon" });

  19:         this.AllProducts.Add(new Product { ProductId = 9, ProductName = "Guava" });

  20:         this.AllProducts.Add(new Product { ProductId = 10, ProductName = "Kiwi" });

  21:         this.AllProducts.Add(new Product { ProductId = 11, ProductName = "Pineapple" });

  22:         this.AllProducts.Add(new Product { ProductId = 12, ProductName = "Mango" });

  23:  

  24:         LoadProductsCommand = new DelegateCommand(LoadProducts, CanLoadProducts);

  25:     }

  26:  

  27:     private void LoadProducts(object param)

  28:     {

  29:         string filter = param as string ?? string.Empty;

  30:         this.Products.Clear();

  31:         var query = from p in this.AllProducts

  32:                     where p.ProductName.ToLower().StartsWith(filter.ToLower())

  33:                     select p;

  34:         foreach (var item in query)

  35:         {

  36:             this.Products.Add(item);

  37:         }

  38:     }

  39:  

  40:     private bool CanLoadProducts(object param)

  41:     {

  42:         return true;

  43:     }

  44:  

  45:     public ICommand LoadProductsCommand { get; set; }

  46:  

  47:     public ObservableCollection<Product> AllProducts { get; set; }

  48:  

  49:     private ObservableCollection<Product> products;

  50:     public ObservableCollection<Product> Products

  51:     {

  52:         get

  53:         {

  54:             return products;

  55:         }

  56:         set

  57:         {

  58:             products = value;

  59:             this.FirePropertyChanged("Product");

  60:         }

  61:     }

  62: }

  63:  

Here is the ViewModelBase class. It simply contains the FirePropertyChanged event that all ViewModel classes will use in my project.

   1: public abstract class ViewModelBase : INotifyPropertyChanged

   2: {

   3:     public ViewModelBase()

   4:     {

   5:     }

   6:  

   7:     public event PropertyChangedEventHandler PropertyChanged;

   8:  

   9:     protected void FirePropertyChanged(string propertyname)

  10:     {

  11:         var handler = PropertyChanged;

  12:         if (handler != null)

  13:             handler(this, new PropertyChangedEventArgs(propertyname));

  14:     }

  15:  

  16: }

tags: Silverlight
  • http://wouldbepolymath.blogspot.com Anonymous

    Sweeeeeeeet !!! Thx a Lot John Papa.
    The write up is Elegant.

  • Anonymous

    John, how do you create a command to handle different events of different controls.
    ie. what if I want a command that is fired on a combobox dropdown selection ?
    ie. what if I want to fire a command on right button click of a button ?

  • http://www.arunmahendrakar.com Anonymous

    Concise and yet very simple to understand… I’m sure this’ll help many.
    Arun

  • http://www.ubervu.com/conversations/johnpapa.net/silverlight/5-simple-steps-to-commanding-in-silverlight/ Anonymous

    This post was mentioned on Twitter by retrogamer4ever: 5 Simple Steps to Commanding in Silverlight http://bit.ly/9B1Kjv

  • http://silverlightips.net/ Anonymous

    Could use one other very simple demonstration on how to implement SelectionIndexchangedevent on view model say listbox with combox :) and both has SelectionIndexChanged event

  • http://johnpapa.net JohnPapa

    There are a couple of ways to implement a Command on other events. 1 way is to implement Commanding on each individual control type. I am not a huge fan of this, though it is simple to do. I just do nto agree with having to do that for every control and event pair.
    Another more common ways to handle it is to implement a behavior in Blend that routes View events to ViewModel commands. Some frameworks also have some techniques, such as the MVVM light toolkit.

  • Anonymous

    DelegateCommand rocks, although I preferer the variation with a generic parameter instead of object.

  • Anonymous

    Hi John,
    This is a great example. Thanks for sharing this. As others have mentioned, if we only needed support for click events that come from a button or such that already has an ICommand event, that would be simple, but usually there are many other event like SelectionChanged and others that also need to be hooked up to the ViewModel. Do you have any examples of using Blend Behaviors as you mention or MVVM Light. There are so many different ways of doing all these things – how do we know which to use? I’m looking for the SL-TV session with Laurent to see some examples of using MVVM Light. Any idea when that will be available? Thanks for all you do for the community. It really helps.
    thanks!
    Bill

  • http://goldytech.wordpress.com Anonymous

    @Steve,
    Please look at my post where I show how to handle the events of the controls in MVVM pattern.
    goldytech.wordpress.com/…/events-handling
    Thanks
    Goldy

  • http://www.liquidjelly.co.uk/supersearch Anonymous

    Great to see that commanding is supported natively in SL4 without having to add references to the PRISM assemblies :-)

  • http://OpenLightGroup.net Anonymous

    Very good. Strait to the point.

  • Anonymous

    I will appreciate it if we can extend this command to datagrid selected row.

  • http://amyotech.spaces.live.com/ Anonymous

    Nice post.
    I used this solution to solve the issue here: forums.silverlight.net/…/163891.aspx

  • http://softwareengineeringservices.com Anonymous

    Here is a slight modification to give you generic parameters:
    public class DelegateCommand<T> : ICommand
    {
    private Func<T, bool> m_canExecute;
    private Action<T> m_executeAction;
    private bool m_canExecuteCache;
    public event EventHandler CanExecuteChanged;
    public DelegateCommand(Action<T> executeAction, Func<T, bool> canExecute)
    {
    m_executeAction = executeAction;
    m_canExecute = canExecute;
    }
    #region ICommand Members
    public bool CanExecute(object parameter)
    {
    bool temp = m_canExecute((T)parameter);
    if (m_canExecuteCache != temp)
    {
    m_canExecuteCache = temp;
    if (CanExecuteChanged != null)
    {
    CanExecuteChanged(this, new EventArgs());
    }
    }
    return m_canExecuteCache;
    }
    public void Execute(object parameter)
    {
    m_executeAction((T)parameter);
    }
    #endregion
    }

  • http://www.calabonga.com Anonymous

    that’s realy what I need in Silverlight3… but now wait Silverlight 4 :)
    thanks, good post

  • http://blueonionsoftware.com/blog.aspx?p=46d67da3-b8a7-4c62-a949-69c10a37d48f Anonymous

    Pingback from Friday Links #90 | Blue Onion Software *

  • http://stevepietrek.com/2010/02/28/links-2282010/ Anonymous

    Pingback from Links (2/28/2010) « Steve Pietrek-Everything SharePoint/Silverlight

  • http://www.davidyardy.com Anonymous

    Very nicely written. Thank you. Would love to see a larger application building on this type of approach dealing with getting data and some additional UI events. Ty

  • http://OpenLightGroup.net Anonymous

    I posted an example that uses this at:
    openlightgroup.net/…/Blend-4-TreeVie

  • danp2

    Great tips – thank you! I just have one problem: when I attach the button in xaml using the Command property, and CanExecute ever returns false, the button will become disabled. After that the button will never become enabled again – maybe I’m doing something wrong..

  • johnthy

    As danp2 points out, there’s something wrong here. CanExecute shouldn’t call CanExecuteChanged; a call to CanExecuteChanged will trigger an evaluation of CanExecute. So one instead needs to expose a NotifyCanExecuteChanged method delegating to the event invocation and get rid of all the stuff in CanExecute.

  • http://johnpapa.net johnpapa.net

    5 simple steps to commanding in silverlight.. Neat :)

  • http://johnpapa.net johnpapa.net

    5 simple steps to commanding in silverlight.. Ho-o-o-o-t :)

  • Saravanan

    Hi,Papa,
    why do we have these type of commands,i want to know these,
    is it very must to use the commands in mvvm pattern,
    please let me know clearly

  • TA

    Using your five steps, any reason why VS2010 would tell me that the ICommand.Execute member was not implemented? the only thing i did different from your code was i added a second object parameter to Action<>

  • Nelson

    Hi,
    And if I use commanding inside DataTemplate? How remove the handler, because I use a lot of commands in my application, and now I have problems of memory leak and as commands are not removed, the references keeps alive and the garbage collector can´t clean the objects.
    How solve this?

  • Saurabh

    Hi John,
    I am facing an issue in ICommand. I have put Button in ListBox (each listboxitem contains one button) and I bind that button command with ICommand which exists in ViewModel but unfortunately that command doesn’t execute.
    Any Idea?
    Kind Regards,
    Saurabh

  • ChhaviNath

    Hi Saurabh,
    u need to add a new column in the itemsource. the type would be Telerik.Windows.Controls.DelegateCommand.
    now for each delegate command assign -
    DeleteItemFromComboCommand = new Telerik.Windows.Controls.DelegateCommand(DeleteItemFromCombo);
    the method DeleteItemFromCombo takes one object parameter.

  • http://www.google.com mike

    only works with buttons. what if i need to fire the Keyup event on a textbox and pass in the text?
    doesnt appear to be a solution for that.

  • amir hamza

    private TContext _DataContext;
    protected virtual TContext DataContext
    {
    get
    {
    if (_DataContext == null)
    {
    _DataContext = new TContext();
    }
    return _DataContext;
    }
    }

  • Sahil

    Very Nice Read. Thanks for posting.

  • Josh Sommers

    Thanks for this John, it is very clear. However, in your viewmodel class, the CanExecute function always returns true. A better example might show a case where it sometimes returns false. What is also missing is how one would go about raising the CanExecuteChanged event when conditions in the viewmodel change. For example, if the command can only execute when a certain property in the VM has a certain value, at what point, and through which methodology would the CanExecuteChanged event in the Command get raised? Would it be best to directly call the CanExecute method of the Command from the setter of said property/properties?

%d bloggers like this: