Creating a Command Behavior for the XamMenuItem

Brian Lagunas / Monday, July 16, 2012

I was playing with the Infragistics XamMenu control today and made a discovery that I did not like.  It does not provide support for commanding!  That’s right; no Command or CommandParameter property that I can use to data bind a command in my ViewModel to.  I couldn’t believe it.  Don’t you worry though.  I will be fixing that immediately.  When I say immediately, I mean as soon as I can.  I have placed an item in the backlog to implement commanding support for the 13.1 release.  Until then, I need a way to data bind my ViewModel commands to a XamMenuItem, so that when the menu item is clicked my command will execute.

There are a few ways to accomplish the task.  I recently blogged about an approach that would work in this scenario which uses attached properties, but I wanted to show another approach that could also work.  For this scenario I am going to be using a custom Behavior.  I like this approach because of it’s simplicity and control of when the behavior is being attached and detached from the object.

Let’s start by creating a new WPF application, or Silverlight if your prefer, and dragging the XamMenu control onto the design surface of our View.  You need to also add a reference to System.Windows.Interactivity.  Your references should look something like this.

xammenu-behavior-references

Now let’s add a ViewModel that will contain our command that will be executed.

public class ViewModel : INotifyPropertyChanged
{
    public ICommand DoSomethingCommand { get; set; }

    public ViewModel()
    {
        DoSomethingCommand = new DelegateCommand(DoSomething);
    }

    private void DoSomething(object param)
    {
        MessageBox.Show(param.ToString());
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

As you can see, this ViewModel is very simple.  We simply have a single command called DoSomethingCommand which is an instance of a DelegateCommand, also commonly known as a RelayCommand.  Now let’s set the DataContext of our View to our ViewModel.  You can do this in code behind, but I will just wire it up in XAML.

<Window x:Class="XamMenuItemCommandBehavior.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:local="clr-namespace:XamMenuItemCommandBehavior"
        Title="MainWindow" Height="350" Width="525" xmlns:ig="http://schemas.infragistics.com/xaml">
    
    <Window.DataContext>
        <local:ViewModel />
    Window.DataContext>
    
    <Grid>
        <ig:XamMenu>
            <ig:XamMenuItem Header="Click Me">

            ig:XamMenuItem>
        ig:XamMenu>
    Grid>
Window>

Notice how I added two namespaces to the View.  One is for the System.Windows.Interactivity, and the other is for our local project where our ViewModel exists.  Now let’s create our behavior.  We are need to create a new class that derives from Behavior, where T is the control you want to attach the behavior to.

public class XamMenuItemCommandBehavior : Behavior<XamMenuItem>
{
    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(XamMenuItemCommandBehavior), null);
    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public static readonly DependencyProperty CommandParamenterProperty = DependencyProperty.Register("CommandParamenter", typeof(object), typeof(XamMenuItemCommandBehavior), null);
    public object CommandParamenter
    {
        get { return (object)GetValue(CommandParamenterProperty); }
        set { SetValue(CommandParamenterProperty, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Click += AssociatedObject_Click;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Click -= AssociatedObject_Click;
        base.OnDetaching();
    }

    private void AssociatedObject_Click(object sender, EventArgs e)
    {
        if (Command != null && Command.CanExecute(CommandParamenter))
            Command.Execute(CommandParamenter);
    }
}

As you can see, I have added two properties,  Command and CommandParameter.  Override the OnAttached method and add an event handler for the AssociatedObject (which is of type T) Click event.  In the Click event handler, we simply add code that checks for a Command, if it can be executed, and then executes the command passing the command parameter.

Lastly, we override the OnDetaching method and unhook our event handler to clean up any possible memory leaks.  Now that we have our Behavior completed, we need to hook it up to our XamMenu.  Add a namespace to the location of your behavior, and then modify your View as follows.

<Window x:Class="XamMenuItemCommandBehavior.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:b="clr-namespace:XamMenuItemCommandBehavior.Behaviors"
        xmlns:local="clr-namespace:XamMenuItemCommandBehavior"
        Title="MainWindow" Height="350" Width="525" xmlns:ig="http://schemas.infragistics.com/xaml">
    
    <Window.DataContext>
        <local:ViewModel />
    Window.DataContext>
    
    <Grid>
        <ig:XamMenu>
            <ig:XamMenuItem Header="Click Me">
                <i:Interaction.Behaviors>
                    <b:XamMenuItemCommandBehavior Command="{Binding DoSomethingCommand}" CommandParamenter="I did something" />
                i:Interaction.Behaviors>
            ig:XamMenuItem>
        ig:XamMenu>
    Grid>
Window>

We are using the Interaction.Behaviors attached property and declaring an instance of our custom XamMenuItemCommandBehavior class.  We data bind the Command property to our DoSomethingCommand that exists in our ViewModel and we are providing a CommapandParameter.  Run the application, click on the XamMenuItem and see the magic happen.

xammenu-behavior-final

Wasn’t that easy?

xammenuitemcommandbehavior.zip