Home > other >  WPF Context Menu, MenuItem Child of Bound MenuItem not showing
WPF Context Menu, MenuItem Child of Bound MenuItem not showing

Time:05-05

I have a ContextMenu with a MenuItem bound to a list. It is supposed to list out the items (which it does). But under each item I am attempting to show another sub-MenuItem with the header "Remove".

Everything works properly except the 'Remove' sub-MenuItem is not showing....

Is there something obvious that I'm missing?

MODEL

public class MockModel
    {
        public string Name { get; set; }
        public MockModel(string name)
        {
            Name = name;
        }
    }

VIEWMODEL

public class MockVm
    {
        public ObservableCollection<MockModel> MockModels { get; set; } = new();

        public MockVm()
        {
            MockModels.Add(new MockModel("Item1"));
            MockModels.Add(new MockModel("Item2"));
            MockModels.Add(new MockModel("Item3"));
        }
    }

CODE BEHIND

public MainWindow()
        {
            InitializeComponent();
            DataContext = new MockVm();
        }

XAML

<Grid>
        <Label Content="XXXXXXXXXXX">
            <Label.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="ItemCollection" ItemsSource="{Binding Path=MockModels}">
                        <MenuItem.ItemTemplate>
                            <DataTemplate>
                                <MenuItem Header="{Binding Path=Name}">

                                    <!--Everything Else works except for this part.-->
                                    <MenuItem Header="Remove"/>

                                </MenuItem>
                            </DataTemplate>
                        </MenuItem.ItemTemplate>
                    </MenuItem>

                </ContextMenu>
            </Label.ContextMenu>
        </Label>
    </Grid>

This is the output, but no sub-item comes up

CodePudding user response:

WPF ContextMenu, MenuItems, and their children, can be quite confusing and frustrating if you don't define them exactly the way the XAML translator wants you to do it. Theoretically, what you defined should work. However, the XAML compiler doesn't handle your interpretation of the xaml. I see this same issue with Triggers, where unless you follow a specific guideline on using them, you'll be confused as to why it doesn't work when you want to define a trigger on a control.

Having said that, this should work:

<Grid>
    <Label Content="XXXXXXXXXXX">
        <Label.Resources>
            <Style x:Key="MockItemContainerStyle" TargetType="MenuItem">
                <Setter Property="Header" Value="{Binding Path=Name}"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="MenuItem">
                            <MenuItem Header="{TemplateBinding Header}">
                                <MenuItem Header="Remove"/>
                            </MenuItem>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Label.Resources>
        <Label.ContextMenu>
            <ContextMenu>
                <MenuItem Header="ItemCollection" ItemsSource="{Binding Path=MockModels}" ItemContainerStyle="{StaticResource MockItemContainerStyle}"/>
            </ContextMenu>
        </Label.ContextMenu>
    </Label>

To me, the above code means the same thing as what you wrote but it is just syntactically different.

CodePudding user response:

The ItemTemplate should not contain a MenuItem element.

Extend your model with a child collection:

public class MockModel
{
    public string Name { get; set; }

    public MockModel(string name)
    {
        Name = name;
        ChildItems = new MockModel[1] { new MockModel() };
    }

    private MockModel()
    {
        Name = "Remove";
    }

    public IEnumerable<MockModel> ChildItems { get; }
}

And use an HierarchicalDataTemplate in the view:

<Label Content="XXXXXXXXXXX">
    <Label.ContextMenu>
        <ContextMenu>
            <MenuItem Header="ItemCollection" ItemsSource="{Binding Path=MockModels}">
                <MenuItem.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding ChildItems}">
                        <TextBlock Text="{Binding Name}" />
                    </HierarchicalDataTemplate>
                </MenuItem.ItemTemplate>
            </MenuItem>

        </ContextMenu>
    </Label.ContextMenu>
</Label>
  • Related