3

I am trying to add an ItemsSource to a MenuItem while keeping the Command bound to my ViewModel (my Window's DataContext). So far, I haven't figured out a way to make it work. Before the ItemsSource is added, the binding is fine. The collection that I am trying to bind comes from a StaticResource. Can anybody help me out with this?

<MenuItem Command="{Binding OpenTeamPage}"
          DisplayMemberPath="Name"
          Header="Teams"
          ItemsSource="{Binding Teams,
                                Source={StaticResource Container}}" />

I have tried using this and variations of it with no luck:

Command="{Binding OpenTeamPage,
                  RelativeSource={RelativeSource AncestorType=Window},
                  Mode=Default}"

If anybody could tell me how to use this ItemsSource while still binding my Command to my ViewModel, I would greatly appreciate it. I suppose I could put the Command in my Team model, but I would like to avoid that if possible.

EDIT : To clarify my problem, with the ItemsSource in place, the command in the ViewModel doesn't fire at all. Without the ItemsSource, the command fires. I would like to be able to have the ItemsSource and still be able to fire the command.

EDIT:

public class GameContainer
{
    static GameContainer()
    {
        Teams = new ObservableCollection<Team>();
    }

    public static ObservableCollection<Team> Teams { get; set; } 
}

In App.xaml:

<data:GameContainer x:Key="Container" />

The collection is populated when the program is started.

My goal once I get this working is to pass the selected team to the Viewmodel, hopefully via CommandParameter, and display info regarding the selected team.

EDIT: I was mistaken in my original post. A bound collection coming from the Viewmodel does not work either.

5
  • do you see child menuitems containing Teams in both case? Commented Oct 25, 2013 at 18:16
  • Yes, they display correctly. Commented Oct 25, 2013 at 18:18
  • Please also post the definition of your resource Container Commented Oct 25, 2013 at 18:34
  • are you sure when you bind the ItemsSource of menuitem to VM property, the command on it works? Commented Oct 25, 2013 at 18:59
  • I actually just modified my post. I was mistaken when I first wrote it. Commented Oct 25, 2013 at 19:00

2 Answers 2

3

This is the behaviour of MenuItem, Item having Child MenuItem won't fire Command and it also should not as it does not make sense. But if you still want to fire a command on Parent Item click,there are two options

  1. You can use Interactivity Triggers on your MenuItem to call command on MouseDown event like

    <MenuItem 
          DisplayMemberPath="Name"
          Header="Teams"
          ItemsSource="{Binding Teams,
                                Source={StaticResource Container}}">
      <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseDown">
            <cmd:EventToCommand Command="{Binding OpenTeamPage}" />
        </i:EventTrigger>
      </i:Interaction.Triggers>
    </MenuItem>
    
  2. you can define a Attached Property for command and define the MenuItem MouseDown behaviour like

     public static class MouseCommandBehavior
     {
    
          public static readonly DependencyProperty MouseDownCommandProperty =
                        DependencyProperty.RegisterAttached("MouseDownCommand",
                        typeof(ICommand),
                        typeof(MouseCommandBehavior),
                        new FrameworkPropertyMetadata(null, (obj, e) => OnMouseCommandChanged(obj, (ICommand)e.NewValue, false)));
    
     public static ICommand GetMouseDownCommand(DependencyObject d)
     {
             return (ICommand)d.GetValue(MouseDownCommandProperty);
     }
    
      public static void SetMouseDownCommand(DependencyObject d, ICommand value)
     {
         d.SetValue(MouseDownCommandProperty, value);
     }
    
     private static void OnMouseCommandChanged(DependencyObject d, ICommand command)
     {
           if (command == null) return;
    
            var element = (FrameworkElement)d;
    
            element.PreviewMouseDown += (obj, e) => command.Execute(null);
      }
     }
    }
    

and you can set this Property value on your menuItem

<MenuItem local:MouseCommandBehavior.MouseDownCommand="{Binding OpenTeamPage}"
      DisplayMemberPath="Name"
      Header="Teams"
      ItemsSource="{Binding Teams,
      Source={StaticResource Container}}">
Sign up to request clarification or add additional context in comments.

1 Comment

This certainly seems like a good approach. Seeing as it does what I need for it to do, I'll gladly accept your answer. One thing, though, is that using the MouseDown event didn't work for me. This did: <i:EventTrigger EventName="Click">. Thanks for your help!
0

MenuItem will not execute its command if it's not a leaf node. Only menu items that are leafs (items with no children) are executing a command.

This is probably done due to convention - when you click an items that has children you get the children shown immediately, otherwise there's a delay from mouse hover till children shown.

Although it's probably a bad idea (from UX point of view) to have command on a parent, it's possible:

<MenuItem DisplayMemberPath="Name"
          Header="{Binding OpenTeamPage}"
          ItemsSource="{Binding Teams, Source={StaticResource Container}}" >
    <MenuItem.HeaderTemplate>
        <DataTemplate>
            <!--Probably need to make this button transparent-->
            <Button Content="Teams"
                    Command="{Binding }"/>
        </DataTemplate>
    </MenuItem.HeaderTemplate>
    <!--This style is for the children to fire the same command as the parent-->
    <MenuItem.ItemContainerStyle>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Command"
                    Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}, Path=Header}"/>
        </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>

Depending upon your design, you'd might need to style the button to be transparent.

2 Comments

This allows for the parent to fire the command but the children still don't respond when clicked.
So you need the parent and the children to fire the same command, right? I've edited the answer for that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.