Databinding an action to code in WPF MVVM can be done in two ways:
ICommand
The simplest is to use an ICommand implementation for the code to execute.
Typically the ICommand implementation has a reference to the VM class, allowing it access to the state. Any changes that are to occur in the interface as a result of the action are accomplished by changes to properties in the VM instance, which are databound to the View.
Here is an example command:
namespace CharacterForms.Command
{
public class CustomerSearchByKey:ICommand
{
CharacterMainViewModel vm;
public CustomerSearchByKey(CharacterMainViewModel _vm)
{
vm = _vm;
}
public bool CanExecute(object parameter)
{
return (vm.Key >=0);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
vm.UnderlyingCharacter = vm.CharacterService
.FetchByKey(vm.Key);
}
}
}
Note the CanExecute property that will control the enabled property of the bound input source.
The above action would be bound to the View as follows:
The VM instance would expose an instance of the command as a property:
public ICommand FetchCommand { get; set; }
Initialised in the VM’s constructor
public CharacterMainViewModel(ICharacterService service)
{
...
FetchCommand = new CustomerSearchByKey(this);
}
And the interface would bind to the instance as follows:
<Button Content="Search"
...
Command="{Binding FetchCommand}" />
Note that the command has a CanExecute property. In order for it to function as you would expect, the text box that is bound to the Key property on the VM object require binding like this:
Text="{Binding Path=Key, UpdateSourceTrigger=PropertyChanged}"
to allow the CanExecute property to be reevaluated when the user types in the box.
WPF Routed Commands
This option allows for more flexible interception off action intentions.
In this case a class is constructed containing the strongly typed command names:
namespace CharacterForms
{
internal static class RoutedAppCommands
{
public static RoutedUICommand DoItCommand;
static RoutedAppCommands()
{
var doItInputs = new InputGestureCollection();
doItInputs.Add(
new KeyGesture(Key.B,
ModifierKeys.Control |
ModifierKeys.Shift)
);
DoItCommand = new RoutedUICommand("Do It",
"DoIt",
typeof(RoutedAppCommands),
doItInputs);
}
}
}
In this case the command definitions are for a single command: DoItCommand.
Bindings are created between actions triggered by input gestures, and code that will execute the intention of the action.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
...
var vm = new ...
this.DataContext = vm;
var doIt = new CommandBinding(RoutedAppCommands.DoItCommand);
doIt.Executed += new ExecutedRoutedEventHandler(vm.doIt_Executed);
CommandBindings.Add(doIt);
}
}
In this case the key ^-shift B is bound to the command, and a method on the VM instance will be executed when the event occurs.
doIt also has a CanExecute property that can be used to control whether the event source is enabled.
The command can also be bound in the xaml to a control:
<Button ... Command="tl:RoutedAppCommands.DoItCommand" />
where tl is the xml namespace added to reference the c# namespace the commands are in. Note that this will execute the same action method as pressing the key.