Search code examples
c#wpfxamlmvvmitemssource

Binding Command to Viewmodel with ItemsSource from a StaticResource


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.


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