5
votes

I have a MenuItem in a context menu which I want to generate sub MenuItems for each item in a list using the ItemSource. Each of these generated items should then also have sub MenuItems Active (checkable), Edit and Delete.

Custom Messages
    -Custom Message 1
           -Active 
           -Edit
           -Delete
    -Custom Message 2
           -Active 
           -Edit
           -Delete
    -Custom Message 3
           -Active 
           -Edit
           -Delete

The following XAML partially works:

<MenuItem Header="Custom Messages" Visibility="{Binding Path=HasCustomMessages, Converter={StaticResource BVC}}" ItemsSource="{Binding Path=CustomMessages}" DisplayMemberPath="Description">
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="ItemsSource">
                <Setter.Value>
                    <x:Array Type="FrameworkElement">
                        <MenuItem Header="Active" IsCheckable="True" IsChecked="{Binding Path=Active}"></MenuItem>
                        <Separator></Separator>
                        <MenuItem Header="Edit" Name="EditCustomMessageButton" Click="EditCustomMessageButton_Click" Style="{x:Null}"></MenuItem>
                        <MenuItem Header="Delete" Name="DeleteCustomMessageButton" Click="DeleteCustomMessageButton_Click" Style="{x:Null}"></MenuItem>
                    </x:Array>
                </Setter.Value>
            </Setter>
        </Style>
    </MenuItem.ItemContainerStyle>                       
</MenuItem>
<MenuItem Header="Add Custom Message" Name="AddCustomMessageButtton" Click="AddCustomMessageButtton_Click"></MenuItem>
<Separator></Separator>
<MenuItem Header="Delete" Name="DeleteButton" Click="DeleteButton_Click"></MenuItem>

However there are two problems:

  1. Edit and Delete seems to be behaving in a recusive manner as they both appear to have sub menus and subsequently throw and exception when hovered over: Sub Menu Exception

  2. By setting ItemSource="{x:Null}" on Edit and Delete this solves the above problem but the events behave strangly. Clicking Delete does nothing and clicking Edit triggers the Edit button click event followed by the Delete button click event and then the Add button click event (which isn't even a sibling of the other two).

3
Is it possible for you to have a VM for each menuItem that contains an ICommand property for the Click event? - tgpdyk

3 Answers

4
votes

The problem is that you set the style of all MenuItemto be the same with the submenu, which cause this infinite recursion hence - StackOverflow :-) issue. The following line is wrong:

<Style TargetType="MenuItem">

So instead you can create this style in your resources and call it by its x:Key:

<Style x:Key="SubMenuStyle">
    <Setter Property="ItemsSource">
        <Setter.Value>
            <x:Array Type="FrameworkElement">
                <MenuItem Header="Active" IsCheckable="True" IsChecked="{Binding Path=Active}"></MenuItem>
                <Separator></Separator>
                <MenuItem Header="Edit" Name="EditCustomMessageButton" Click="EditCustomMessageButton_Click" Style="{x:Null}"></MenuItem>
                <MenuItem Header="Delete" Name="DeleteCustomMessageButton" Click="DeleteCustomMessageButton_Click" Style="{x:Null}"></MenuItem>
            </x:Array>
        </Setter.Value>
    </Setter>
</Style>


<MenuItem Header="Custom Messages" ItemsSource="{Binding Path=CustomMessages}" ItemContainerStyle="{StaticResource SubMenuStyle}"...>
0
votes

The answers here didn't work for me at all. What worked is an approach from this answer.

What I did was I created a simple template selector like so:

public class MenuItemContainerTemplateSelector : ItemContainerTemplateSelector
{
    public string TemplateKey { get; set; }

    public override DataTemplate SelectTemplate(object item, ItemsControl parentItemsControl)
    {
        return (DataTemplate) parentItemsControl.FindResource(TemplateKey);
    }
}

Then the whole menu construction looks something like this:

<Menu>
    <Menu.Resources>
        <DataTemplate x:Key="ItemWithSubmenu" DataType="{x:Type ItemViewModel}">
            <MenuItem Header="{Binding HeaderProperty}">
                <MenuItem Header="Active" IsCheckable="True" IsChecked="{Binding Path=Active}" />
                <Separator />
                <MenuItem Header="Edit" Click="EditCustomMessageButton_Click" />
                <MenuItem Header="Delete" Command="{Binding DeleteCommand}" />
            </MenuItem>
        </DataTemplate>

        <main:MenuItemContainerTemplateSelector TemplateKey="ItemWithSubmenu" x:Key="ItemWithSubmenuSelector" />
    </Menu.Resources>

    ...
    <MenuItem Header="Custom Messages" ItemsSource="{Binding CustomMessages}" ItemContainerTemplateSelector="{StaticResource ItemWithSubmenuSelector}" UsesItemContainerTemplate="True" />
    ...
</Menu>
-2
votes

First, you have set ItemsSource property two times in your code above as ItemsSource="{Binding Path=CustomMessages}".

Secondly, You are setting ItemsSource the wrong way. It should be :

<MenuItem ...>
<MenuItem.ItemsSource>
 <x:Array Type="FrameworkElement">
   <MenuItem Header="Active" IsCheckable="True" IsChecked="{Binding Path=Active}"></MenuItem>
   <Separator></Separator>
   <MenuItem Header="Edit" Name="EditCustomMessageButton" Style="{x:Null}"></MenuItem>
   <MenuItem Header="Delete" Name="DeleteCustomMessageButton" Style="{x:Null}"></MenuItem>
 </x:Array>
</MenuItem.ItemsSource>