A simple WPF TriggerAction to turn events into commands

This is nothing new. I know of several MVVM frameworks that do this, but this was my take on a solution for the following:

So you have events on a UIElement, for example a Button has MouseEnter and MouseLeave (amongst others). By default the events require an event handler which would might be placed in the “code behind” in the view itself. But this is no use if, for example a MouseEnter should update some data from the view model unless you want to do more coding in the view to access the view model and makes calls directly on it, which is a somewhat against the spirit of MVVM. So what would be cool is if the MouseEnter could instead be bound to a view model command instead.

Being that part of the mechanism already exists in EventTriggers then we just need to supply a trigger action to bind to the view model.

For example the XAML might look like:

<Button Content="Cancel" Width="80" Margin="3" >
   <i:Interaction.Triggers>
      <i:EventTrigger EventName="MouseEnter">
         <controls:CommandAction Command="{Binding ClearSearch}" />
      </i:EventTrigger>
   </i:Interaction.Triggers>
</Button>

The code for the TriggerAction is simple

public class CommandAction : TriggerAction<DependencyObject>
{
   public static readonly DependencyProperty CommandProperty =
	DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandAction),
	new PropertyMetadata(null, OnCommandChanged));

   public static readonly DependencyProperty CommandParameterProperty =
	DependencyProperty.Register("CommandParameter", typeof(object), typeof(CommandAction),
	new PropertyMetadata(null, OnCommandParameterChanged));

   private IDisposable canExecuteChanged;

   public ICommand Command
   {
      get { return (ICommand)GetValue(CommandProperty); }
      set { SetValue(CommandProperty, value); }
   }

   public object CommandParameter
   {
      get { return GetValue(CommandParameterProperty); }
      set { SetValue(CommandParameterProperty, value); }
   }

   private static void OnCommandChanged(DependencyObject sender, 
                   DependencyPropertyChangedEventArgs e)
   {
      CommandAction ev = sender as CommandAction;
      if(ev != null)
      {
         if (ev.canExecuteChanged != null)
	 {
	    ev.canExecuteChanged.Dispose();
	 }

	 ICommand command = e.NewValue as ICommand;
	 if (command != null)
	 {
	    ev.canExecuteChanged = Observable.FromEventPattern(
			x => command.CanExecuteChanged += x,
			x => command.CanExecuteChanged -= x).Subscribe
			(_ => ev.SynchronizeElementState());
	 }
      }
   }

   private static void OnCommandParameterChanged(DependencyObject sender,
            DependencyPropertyChangedEventArgs e)
   {
      CommandAction ev = sender as CommandAction;
      if (ev != null)
      {
         ev.SynchronizeElementState();
      }
   }

   private void SynchronizeElementState()
   {
      ICommand command = Command;
      if (command != null)
      {
         FrameworkElement associatedObject = AssociatedObject as FrameworkElement;
	 if (associatedObject != null)
	 {
	    associatedObject.IsEnabled = command.CanExecute(CommandParameter);
	 }
      }	
   }

   protected override void Invoke(object parameter)
   {
      ICommand command = Command;
      if(command != null)
      {
         command.Execute(CommandParameter);
      }
   }
}

We derive our class from TriggerAction and declare any dependency properties etc. we want on it. So if you ignore all the setting up of Command & CommandParameter code, this really boils down to the override of the Invoke method. This is what’s called when the trigger condition is met.