Question

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.

Was it helpful?

Solution

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}}">

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top