23

I have a context menu. It's bound to some collection and it has a defined ItemTemplate like this:

<ContextMenu
    ItemsSource={Binding ...}
    ItemTemplate={StaticResource itemTemplate}
    />

itemTemplate is a simple DataTemplate with a TextBlock:

<DataTemplate x:Key="itemTemplate">
    <TextBlock Text={Binding ...} />
</DataTemplate>

How do I bind Command property for MenuItem to the underlying object's property?

arconaut
  • 3,227
  • 2
  • 27
  • 36

3 Answers3

27

I think you need to wrap your TextBlock in a MenuItem:

<DataTemplate x:Key="itemTemplate">
    <MenuItem Command={Binding ...}>
        <TextBlock Text={Binding ...} />
    </MenuItem>
</DataTemplate>

But I don't have an IDE in front of me right now to try this. Let me know how it goes.


Looks like you need to use the ItemContainerStyle as seen here. Sorry for leading you down the wrong path at the start there - but I got in front of an IDE and this works:

<ContextMenu.ItemContainerStyle>
    <Style TargetType="MenuItem">
        <Setter Property="Command" Value="{Binding ...}"/>
    </Style>
</ContextMenu.ItemContainerStyle>
Martin Harris
  • 28,277
  • 7
  • 90
  • 101
  • 3
    Actually, this will add TextBlock to the MenuItem's Items collection. And it also puts MenuItem inside of another MenuItem. – arconaut May 22 '09 at 17:04
  • But with your post I started thinking of templating MenuItem itself, this could be what i need. – arconaut May 22 '09 at 17:06
  • 6
    This creates double MenuItem's, which f*cks up styling! Don't think this is an appropriate answer! – Kolky Nov 21 '11 at 10:31
  • 1
    @Kolky - Read the second part of the answer where I correct myself. I didn't remove the incorrect first half because it had already been commented on. – Martin Harris Nov 21 '11 at 10:32
  • 1
    Excuse me for my first reaction; that second solution is indeed working. – Kolky Nov 23 '11 at 12:25
  • 3
    What if there is more than one menuitem and we need to bind the menu items with individual commands. – TrustyCoder Nov 16 '12 at 23:01
7

Although this is only a slight variation on Martin Harris's answer, I thought I'd share it anyway. I found it more useful specify a single command for the whole collection and also send along a CommandParameter:

<MenuItem.ItemContainerStyle>
    <Style TargetType="MenuItem">
       <Setter Property="Command" Value="{x:Static v:ViewModel.CommandForAll}"/>
       <Setter Property="CommandParameter" Value="{Binding ValueForCommand}"/>
    </Style>
</MenuItem.ItemContainerStyle>

Then you can determine what to do in the handler for the command:

private void CommandForAll_Executed(object sender, ExecutedRoutedEventArgs e)
{
    var cmdParam = e.Paramater as ExpectedType
    if (cmdParam != null)
        //DoStuff...
}
MatrixManAtYrService
  • 8,023
  • 1
  • 50
  • 61
0

I realize I'm answering this quite a bit after the fact, but I ran into the same problem and the previous answers seemed to make binding to multiple different commands difficult. The solution I arrived is very similar to MatrixManAtYrService's and works in 3 parts:

1) Bind the command using the ItemContainerStyle property to a command in the ViewModel -- this is the same as the previous answers. One exception is that I bind the CommandParameter to the MenuItem.

<Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self}}"/>

2) Create a custom class to define the look and behavior of each MenuItem. The ItemsSource of the menu will be set to a list of these. This is the same as other answers. However, in my implementation I have given the class an Action to be executed when the MenuItemCommand is invoked. I also included a boolean that will allow the MenuItem to be disabled.

public class MenuAction
{
    public string Name { get => name; set => name = value; }
    public Action Action { get => action; set => action = value; }
    public bool CanExecute { get => canExecute; set => canExecute = value; }
}

3) In the command implementation route control to the delegates in MenuAction.

public void HandleCommand(object sender)
{
    MenuItem clickedMenuItem = sender as MenuItem;
    MenuAction menuAction = clickedMenuItem?.DataContext as MenuAction;
    if(menuAction != null)
        menuAction.Action();
}

public bool CanMenuItemExecute(object sender)
{
    MenuItem clickedMenuItem = sender as MenuItem;
    MenuAction menuAction = clickedMenuItem?.DataContext as MenuAction;
    if (menuAction != null)
        return menuAction.CanExecute;
    else
        return false;
}

This should allow you to define all of the behavior of your commands in a list. While it is technically binding to a single command it is functionally similar to having multiple different commands. The same method should also work with nested MenuItems and HierarchicalDataTemplates with some tweaking.

Arc2066
  • 183
  • 7