views:

409

answers:

2

Hi,

I am fairly new to WPF and am struggling a little with a scenario. I have a menu which has menu items. When one of these menu items gets clicked a method needs to be called that will do something based upon the text displayed associated with that menu item. So for example, the menu item's content was "test" so I would need to do something with "test". FYI, this "something" directly affects a collection on the ViewModel.

This is easy to achieve using the click event and no ViewModel, but I was trying to implement MVVM using an explicit ViewModel. So I started to look into Commands but cannot see how I would pass anything from the View back into the Command in the ViewModel.

Any suggestions on what I should be doing here?

Thanks

A: 

You have two choices.

  1. Expose an ICommand for each menu command, such as "FileCommand", "EditCommand", "SaveCommand", etc.
  2. Use the CommandParameter to send information back to the Command, such as

<MenuItem Command="{Binding MenuCommand}" CommandParameter="File">File</MenuItem>

I think the first option is better, as it avoids magic strings.

Will
OK, thanks for the reply. I forgot to mention that the text displayed by the menu items were bound to the ViewModel as well i.e. an ObervableCollection. This would certainly rule out No.2.I am not sure I totally understand No.1? I create a command that implements the ICommand interface, but how does the text contained get passed to the command?Thanks again
Jon Archway
@jon I'm assuming the accepted answer made it clear to you.
Will
+2  A: 

Given that you have a collection of items driving the commanding I would recommend using something similar to Will's second suggestion like this:

<MenuItem Command="{Binding MenuCommand}" CommandParameter="{Binding}" Header="{Binding DisplayText}"/>

On the ViewModel side you can use a DelegateCommand or RelayCommand to hook up your handler method. This allows you to inspect the menu item's data and do whatever you need to based on what's in it.

public DelegateCommand<MyMenuObject> MenuCommand { get; private set; }

public ViewModel()
{
    MenuCommand = new DelegateCommand<MyMenuObject>(MenuCommandExecuted);
}

public void MenuCommandExecuted(MyMenuObject parameter)
{
    // do something based on the parameter object
}

You would also need to either pass MenuCommand into an ICommand property on your collection items to use the simple Binding form above or change the command binding to use something like a RelativeSource FindAncestor to look up the tree to the parent's DataContext (ViewModel) for the MenuCommand. Using this approach gives you flexibility to add or remove items from the collection and not need to make any UI changes to support the new set of items.

Prism DelegateCommand

RelayCommand

John Bowen