Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically binding to ViewModel commands on Window's MenuItem

Working on a WPF application using the MVVM structure.

My Window displays a menu and the current ViewModel. On one of the Menu's MenuItems, I want to list some Commands found in the current ViewModel. The commands listed in the Menu will change depending on the ViewModel.

I got this to work just fine, but the style is messed up - the Command MenuItems are inside another menu box or something. I'll attach a screenshot.

I wrapped the ViewModel's ICommand objects (RelayCommands, in this instance) in CommandViewModel, which expose the Command and the Display string I want on the menu. These CommandViewModels are in a list: CurrentWorkspace.AdditionalOptionsCommands.

Here is the XAML for the Menu. Like I said, it works, it shows the right items and the commands are executed. The display is just incorrect - can anybody tell me why and how to fix it? See the screenshot.

<Menu>
    <MenuItem Header="_Additional Options..." ItemsSource="{Binding Path=CurrentWorkspace.AdditionalOptionsCommands}">
        <MenuItem.ItemTemplate>
            <DataTemplate DataType="{x:Type vm:CommandViewModel}">
                <MenuItem Header="{Binding Path=DisplayText}" Command="{Binding Path=Command}"/>
            </DataTemplate>
        </MenuItem.ItemTemplate>
    </MenuItem>
    <MenuItem Header="_Testing">
        <MenuItem Header="This looks right" />
        <MenuItem Header="This looks right" />
    </MenuItem>   
</Menu>  

Current Appearance:

Current Appearance

Desired Appearance:

Desired Appearance

like image 794
Pieter Müller Avatar asked May 27 '11 15:05

Pieter Müller


1 Answers

This is because when you specify menu items via ItemsSource each item gets automatically wrapped into a MenuItem object. This way the content defined in the DataTemplate (MenuItem element) gets wrapped into one more MenuItem.

What you need to do instead of defining a DataTemplate is to define a style for the MenuItem where you setup bindings to the view model's properties and use this style as ItemContainerStyle on the parent MenuItem:

<Window.Resources>
    <Style x:Key="CommandMenuItemStyle"
           TargetType="{x:Type MenuItem}">
         <Setter Property="Header"
                 Value="{Binding Path=DisplayText}"/> 
         <Setter Property="Command"
                 Value="{Binding Path=Command}"/>
    </Style>
</Window.Resources>
...
<Menu>
    <MenuItem Header="_Additional Options..." 
              ItemsSource="{Binding Path=CurrentWorkspace.AdditionalOptionsCommands}" 
              ItemContainerStyle="{StaticResource CommandMenuItemStyle}"/>
    <MenuItem Header="_Testing">
        <MenuItem Header="This looks right" />
        <MenuItem Header="This looks right" />
    </MenuItem>   
</Menu>   

See http://drwpf.com/blog/2008/03/25/itemscontrol-i-is-for-item-container/ for an in-depth explanation on how item containers work with ItemsControl controls.

like image 200
Pavlo Glazkov Avatar answered Oct 27 '22 17:10

Pavlo Glazkov