To extend the MVVM idea, it is necessary to move more code from
code-behind of the View to the ViewModel. In the first part we have seen how the properties from the ViewModel can be binded to the View and how changes can be notified.
Now we will see how to move click event handler from
code-behind of the View to the ViewModel. Therefore the
Command property in
XAML of the View is used instead of the click event. The property is set to an instance of an implementation of
ICommand. For that we want to have a reusable implementation. One way is to use the
DelegateCommand that is also used in the
Prism Class Library, the usage is described
here. But we want to focus on the simpler implementation of
RelayCommand. The
RelayCommand builds on
WPF Commanding.
public class RelayCommand : ICommand
{
private readonly Action<object> _Execute;
private readonly Func<object, bool> _CanExecute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute", "Execute cannot be null.");
}
_Execute = execute;
_CanExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_Execute(parameter);
}
public bool CanExecute(object parameter)
{
if (_CanExecute == null)
{
return true;
}
return _CanExecute(parameter);
}
}
The
RelayCommand implements the interface
ICommand. Therefore we have to implement the methods Execute and CanExecute. These methods call other methods that you have passed as
Action and
Func generic delegate to the constructor of the
RelayCommand class. Furthermore we have to implement the CanExecuteChanged event. Execute can only be called if CanExecute returns true. If CanExecute depends on one or more properties, then on each change of one of these properties CanExecuteChanged have to be fired so that CanExecute is checked again. To simplify and to automate firing the event, the event is hooked to the static
RequerySuggested event of the
CommandManager. Doing so the CanExecuteChanged event is called after each action in the UI. In some cases you want to call the CanExecuteChanged event manually (such as CanExecute doesn't depends only on UI properties). Therefore the event hook can be removed and a method is added that can be called manually.
public event EventHandler CanExecuteChanged;
public void OnCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, new EventArgs());
}
}
Using the
RelayCommand we can move click event handler to the ViewModel. Therefore we add a property whose type is of
ICommand.
public ICommand LoginCommand
{
get;
private set;
}
The
ICommand will be instantiated in the constructor.
LoginCommand = new RelayCommand(Login, CanLogin);
The Execute method of the
RelayCommand will call Login.
private void Login(object parameter)
{
var passwordContainer = parameter as IHavePassword;
if (passwordContainer != null)
{
var secureString = passwordContainer.Password;
PasswordInVM = ConvertToUnsecureString(secureString);
}
}
While the CanExecute method of the
RelayCommand will call CanLogin.
private bool CanLogin(object parameter)
{
return !string.IsNullOrEmpty(UserName);
}
At last we need only to add the right
Command by binding to the View. We can also pass through a parameter by using
CommandParameter. The parameter is set to both methods, Execute and CanExecute.
<Button x:Name="Login"
Content="Login"
Command="{Binding LoginCommand}"
CommandParameter="{Binding ElementName=This}" />
With the RelayCommand class we have our second component of our own MVVM-Framework.
Further Posts
- WPF and MVVM - Fundamentals
- WPF and MVVM - Commands
- WPF and MVVM - Events