Business Oriented Software Solutions or : "How to best compose processes & technologies to deliver fast time to market, feature and user oriented, high quality software solutions"
Model-View-ViewModel Design Pattern - An implementation of RelayCommand for SilverLight
A common pattern for developping applications with SilverLight and WPF is the Model-View-ViewModel (MVVM) Design Pattern. The MVVP pattern is an evolution of the MVC and MVP well-known pattern, specially adapted to the advanced data binding features of WPF and SilverLight. Please refer to the following excellent MSDN article from Josh Smith for a complete description and implementation of the MVVM Pattern for WPF:
However, as stated in this article title, we're talking about an MVVM pattern for WPF. For those who have tried to develop portable applications working on both WPF and SilverLight, you know this frustration of discovering small differences between WPF and SilverLight and missing classes in SilverLight as compared to WPF.
And in our specific case, Josh defines a RelayCommand class, used to simplified the binding with user interface elements commands with underlying actions in the ViewModel class.
Here is the definition of the RelayCommand class:
public class RelayCommand : ICommand
{
#region Fields
readonly Action
This class makes use of the CommandManager object and the RequerySuggested event. When a user actions the UI in WPF, this triggers the CommandManager to requery all the commands. In Silverlight the CommandManager class does not exist: you have to do the work yourself!
So I created the following RelayCommand implementation, working for SilverLight:
public class RelayCommand : ICommand
{
#region Fields
readonly Action _execute;
readonly Predicate _canExecute;
///
/// In WPF we could use CommandManager. Does not work with SilverLight. Using this ICommandManager interface provides an alternative working for both SilverLight and WPF
///
readonly ICommandManager _commandManager;
#endregion // Fields
#region Constructors
///
/// Creates a new command that can always execute.
///
/// The execution logic.
public RelayCommand(Action execute, ICommandManager commandManager)
: this(execute, null, commandManager)
{
}
///
/// Creates a new command.
///
/// The execution logic.
/// The execution status logic.
public RelayCommand(Action execute, Predicate canExecute, ICommandManager commandManager)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
_commandManager = commandManager;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { _commandManager.RequerySuggested += value; }
remove { _commandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
}
And here is the definition of the ICommandManager interface:
public interface ICommandManager
{
event EventHandler RequerySuggested;
}
Now when creating a new command, you should pass a reference to an object implementing the ICommandManager interface. This object will usually be the ViewModel class itself. It is then the responsability of the ViewModel class to trigger the RequerySuggested event when anything in the state of the ViewModel changed that requires the command to be rebinded.
That's it, this completes the SilverLight implementation of the MVVM pattern.
Comments
You can follow this conversation by subscribing to the comment feed for this post.
Comments
You can follow this conversation by subscribing to the comment feed for this post.