Home > .Net, Prism, WPF > Command Behaviours

Command Behaviours

June 29th, 2009

One of the challenges I have found when using MVVM in Prism, is that out of the box it only supports the click event. Luckily there is an extensibility point here using the CommandBehaviourBase class which means we can tie command execution to any event the control can raise and then bind this using an attached property in the XAML.

There are 3 parts to the code – the example I am going to use is the SelectionChanged event of the ListBox control.

namespace PrismExtension.CommandBehaviours
{
  public class SelectedChangedBehaviour : CommandBehaviorBase<listbox>
  {
     public SelectedChangedBehaviour(ListBox element) : base(element)
     {
        element.SelectionChanged += new SelectionChangedEventHandler(element_SelectedChanged);
      }

      private void element_SelectedChanged(object sender, SelectionChangedEventArgs e)
      {
        base.ExecuteCommand();
      }
    }
}



This code is pretty simple in what it does. The constructor takes an instance of the control you want to attach the event handling code to. The event handling code then executes the command when the event you are watching for is fired. The next part is a bit more tricky.


In order to get this into the XAML as an attached property we need to create a static class.

namespace PrismExtension.CommandBehaviours
{
  public static class SelectedChanged
  {      
     public static ICommand GetCommand(DependencyObject obj)
     {            
        return (ICommand)obj.GetValue(CommandProperty);        
     }          

     public static void SetCommand(DependencyObject obj, ICommand value)        
     {            
        obj.SetValue(CommandProperty, value);        
     }          

     public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(SelectedChanged), new PropertyMetadata(OnSetCommandCallback));          

     public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached("CommandParameter",typeof(object),typeof(SelectedChanged), new PropertyMetadata(OnSetCommandParameterCallback));          

      private static void OnSetCommandCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)        
      {            
          ListBox element = dependencyObject as ListBox;            
          if (element != null)
          {                
              SelectedChangedBehaviour behavior = GetOrCreateBehavior(element);                          
              behavior.Command = e.NewValue as ICommand;            
           }
     }          

     public static void SetCommandParameter(ListBox listbox, object parameter)
     {            
          listbox.SetValue(CommandParameterProperty, parameter);        
      }        

      public static object GetCommandParameter(ListBox listbox)
      {            
          return listbox.GetValue(CommandParameterProperty);        
      }          

      private static SelectedChangedBehaviour GetOrCreateBehavior(ListBox element)
      {            
          SelectedChangedBehaviour behavior = element.GetValue(SelectedIndexChangedBehaviourProperty) as SelectedChangedBehaviour;            
           if (behavior == null)            
           {                
               behavior = new SelectedChangedBehaviour(element);                    
               element.SetValue(SelectedIndexChangedBehaviourProperty, behavior);            
            }
            return behavior;        
       }

       private static void OnSetCommandParameterCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)        
       {            
           ListBox listbox = dependencyObject as ListBox;            
           if (listbox != null)            
           {                
                 SelectedChangedBehaviour behavior = GetOrCreateBehavior(listbox);
                 behavior.CommandParameter = e.NewValue;            
           }        
        }          

         public static SelectedChangedBehaviour GetSelectedIndexChangedBehaviour(DependencyObject obj)    
         {            
             return (SelectedChangedBehaviour)obj.GetValue(SelectedIndexChangedBehaviourProperty);        
         }

          public static void SetSelectedIndexChangedBehaviour(DependencyObject obj, SelectedChangedBehaviour value)        
          {            
             obj.SetValue(SelectedIndexChangedBehaviourProperty, value);        
          }

          public static readonly DependencyProperty SelectedIndexChangedBehaviourProperty =             DependencyProperty.RegisterAttached("SelectedIndexChangedBehaviour",             typeof(SelectedChangedBehaviour), typeof(SelectedChanged), null);    
    }
}


Essentially this consists of a Dependency Property for the command and another one for the CommandParameter. The last part is to actually bind to it in XAML. First add the namespace to the xaml file

xmlns:xt="clr-namespace:PrismExtension.CommandBehaviours;assembly=PrismExtension"


Then in a control that is derived from ListBox this is the code I have used to bind the command to the control

<ListView Name="notesListView"
        xt:SelectedChanged.Command="{Binding SelectedNoteCommand}"
    xt:SelectedChanged.CommandParameter="{Binding ElementName=notesListView}">



On my viewmodel for the view I have a command called SelectedNoteCommand exposed as a read-only property which is the command that the control will fire on the selected item changing.

I pulled this together from a couple of sources – one is the click command itself from inside the Prism code. The second was a really informative video found here by Erik Mork of Silver Bay Labs. Also worth checking out if you are playing around with CommandBehaviours is nRoute because here you will find implementations of a whole swathe of CommandBehaviours! In fact check out nRoute anyway, as the guy writing it is a freaking Genius! The Office 2010 demo app is just beautiful.

PeteDoesStuff.NET .Net, Prism, WPF , ,

  1. No comments yet.
  1. No trackbacks yet.