In my ViewModel I have two commands:
ICommand ExecuteMeOnCheck { get; }
ICommand ExecuteMeOnUncheck { get; }
I wish to attach these commands to a CheckBox and have one of them execute when it is checked and the other execute when it is unchecked. What's the best way to achieve this without cluttering the View with code-behind?
The simplest way I have found to do this involves borrowing a bunch of code. I also think that you do not want to expose two events for the state change. Make your command CheckedChangedCommand instead of Checked and Unchecked. Bind the CheckBox.IsChecked dependency property to a property on your ViewModelClass. That way when your command gets executed, you just check that value in your ViewModel.
First, start using DelegateCommand from the WPF ViewModel toolkit. It isn't clear from your post whether you are or not.
Next, download the .zip archive from the Downloads tab at this link.
The archive has a class called EventBehaviourFactory that makes setting the DependencyProperty easier. Back on the Home tab at the above link, Samuel tells you how to wire up the Command in your XAML to the ViewModel. Here it is:
<TextBox ff:TextBoxBehaviour.TextChangedCommand="{Binding TextChanged}"/>
I used the three classes (DelegateCommand, EventBehaviourFactory and TextBoxBehaviour) line for line and had the TextChanged event working in my project in about five minutes.
The pattern for extending it to other controls like you need to do is easy too. I managed to wire up ListBox.SelectionChanged the same way. Create a new ControlBehaviour class and substitute "Control" for "TextBox" in all the instances and attach the DependencyProperty to the new event.
It is a beautiful thing when your code behind is empty!
I did this with a Trigger on "IsChecked" that sets the Command.
e.g.
<Style x:Key="checkBoxStyle" TargetType="{x:Type CheckBox}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Command"
Value="{Binding AddThingCommand}" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Command"
Value="{Binding RemoveThingCommand}" />
</Trigger>
</Style.Triggers>
</Style>
Another solution, similar to Eddie's : the Attached Command Behaviours by Marlon Grech
You could also use the CheckBox's Command property to attach only one command, in which you test whether the checkbox is checked...
Or you could bind the IsChecked property to a property of your ViewModel, and react to the change in the setter of that property.
This relates to Eddie's answer.
I played around with it a bit and it is great I also created a little template for creating new commands. I'm using it with Sharpdevelop as a code snippet. Just paste the following into your code (e.g.via a snippet):
#region $nameCommand
public static readonly DependencyProperty $nameCommand =
EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
Control.$nameEvent, "$nameCommand", typeof (ControlBehavior));
public static void Set$nameCommand(DependencyObject o, ICommand value)
{
o.SetValue($nameCommand, value);
}
public static ICommand Get$nameCommand(DependencyObject o)
{
return o.GetValue($nameCommand) as ICommand;
}
#endregion
Then do a search replace for "$name" with the name of the Event/Command e.g. MouseEnter
ote, it is importand, that you make sure you pick the right classname for the owner (in my case ControlBehavior.
I am attaching a class I created for common Mouse commands in the hopes that other people share as well and we don't just implement the same thing over and over, where we could have saved a lot of time by sharing. Here my complete ControlBehavior class (I did only implement the events that I needed so far):
public static class ControlBehavior
{
#region MouseEnterCommand
public static readonly DependencyProperty MouseEnterCommand =
EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
Control.MouseEnterEvent, "MouseEnterCommand", typeof (ControlBehavior));
public static void SetMouseEnterCommand(DependencyObject o, ICommand value)
{
o.SetValue(MouseEnterCommand, value);
}
public static ICommand GetMouseEnterCommand(DependencyObject o)
{
return o.GetValue(MouseEnterCommand) as ICommand;
}
#endregion
#region MouseLeaveCommand
public static readonly DependencyProperty MouseLeaveCommand =
EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
Control.MouseLeaveEvent, "MouseLeaveCommand", typeof (ControlBehavior));
public static void SetMouseLeaveCommand(DependencyObject o, ICommand value)
{
o.SetValue(MouseLeaveCommand, value);
}
public static ICommand GetMouseLeaveCommand(DependencyObject o)
{
return o.GetValue(MouseLeaveCommand) as ICommand;
}
#endregion
#region MouseDoubleClickCommand
public static readonly DependencyProperty MouseDoubleClickCommand =
EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
Control.MouseDoubleClickEvent, "MouseDoubleClickCommand", typeof (ControlBehavior));
public static void SetMouseDoubleClickCommand(Control o, ICommand command)
{
o.SetValue(MouseDoubleClickCommand, command);
}
public static void GetMouseDoubleClickCommand(Control o)
{
o.GetValue(MouseDoubleClickCommand);
}
#endregion
#region MouseLeftButtonDownCommand
public static readonly DependencyProperty MouseLeftButtonDownCommand =
EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
Control.MouseLeftButtonDownEvent, "MouseLeftButtonDownCommand", typeof (ControlBehavior));
public static void SetMouseLeftButtonDownCommand(DependencyObject o, ICommand value)
{
o.SetValue(MouseLeftButtonDownCommand, value);
}
public static ICommand GetMouseLeftButtonDownCommand(DependencyObject o)
{
return o.GetValue(MouseLeftButtonDownCommand) as ICommand;
}
#endregion
}
By using above template it took me only a few seconds for each command.
well you can inherit from the checkBox control, add the two commands as properties (Dependency Propertiess) and then override the OnChecked and OnUnchecked methods and trigger each command in the appropriate place