Monday 28 June 2010

Using Commands in Silverlight

Commands in Silverlight are a valuable way of getting away from the code-behind, event handler trap and keeping the UI decoupled from application logic. When used in combination with the MVVM pattern, what would have been event handlers are now effectively properties on the ViewModel (properties that return an object that implements ICommand), bound to the Command property of UI elements such as buttons.
Note: The command approach works well for instances where a UI element is clicked (e.g. buttons) so the resulting code (the command) is executed once. In cases where values are constantly changing (e.g. the value of a slider control) the command approach falls down; you can’t attach a command to a UI element event handler. For such event-driven scenarios you need to use a different approaches: use behaviours, bind the changing value to a property in the ViewModel that in turn updates other bound properties when changed, or create user controls and create dependency properties for the changing values which are bound via the ViewModel.
See http://thejoyofcode.com/Animating_when_Data_Changes_Part_II.aspx.
Before going further be aware that Prism (the Composite Application Library) already has some support for commanding. The Composite Application Library provides the DelegateCommand and CompositeCommand classes to simplify command implementation.
See the Commands technical overview: http://msdn.microsoft.com/en-us/library/dd458928.aspx
A DelegateCommand implementation might look something like this:
public class DelegateCommand : ICommand { private Func<object, bool> _canExecuteFunc;
    private Action<object> _executeAction;
    private bool _canExecute;
    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecuteFunc)
    {
        _executeAction = executeAction;
        _canExecuteFunc = canExecuteFunc;
    }

    public bool CanExecute(object parameter)
    {
        bool temp = _canExecuteFunc(parameter);
        if (_canExecute != temp)
        {
            _canExecute = temp;
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, new EventArgs());
            }
        }
        return _canExecute;
    }
  
    public void Execute(object parameter)
    {
        _executeAction(parameter);
    }
}
To use a DelegateCommand you then need to define a command property on the view model:
public ICommand MyCommand { get; set; }
and then instantiate a DelegateCommand passing in the appropriate methods for CanExecute and Execute:
LoadProductsCommand = new DelegateCommand(MyMethod, CanExecuteMyMethod);
The DelegateCommand can be bound to a UI control:
<Button Content="Push Me" Command="{Binding MyCommand}" />
It is possible to pass parameters to the command:
<Button Content="Push Me" Command="{Binding MyCommand}" CommandParameter="{Binding ElementName=SomeUiEelement, Path=Text}" />
Monday 28 June 2010