WPF MenuItem template for MVVM

I am having trouble recording xaml views so that I can bind ViewModel for cascading menus to my background

here is VM:

public class MenuNode { public string Header {get;} public List<MenuNode> Items {get;} } 

xaml i have:

 <ContextMenu ItemsSource="{Binding Choices}" > <ContextMenu.Resources> <DataTemplate DataType="{x:Type vmi:MenuNode}"> <MenuItem Header="{Binding Header}" ItemsSource="{Binding Items}"/> </DataTemplate> </ContextMenu.Resources> </ContextMenu> 

When the menu appears, I get the first level entries with an arrow (indicating that there should be a submenu), but when I hover over the menu, it does not display the submenu items.

Any ideas?

+4
source share
3 answers

OK, here is the problem:

For some reason, the MenuItems that were generated by your DataTemplate are wrapped inside another MenuItem (the result was nested by MenuItems ). Sub-items did not open because the external MenuItem had no children.

The solution is to use the HierarchicalDataTemplate instead:

 <ContextMenu ItemsSource="{Binding Choices}" > <ContextMenu.Resources> <HierarchicalDataTemplate DataType="{x:Type vmi:MenuNode}" ItemsSource="{Binding Items}"> <TextBlock Text="{Binding Header}"/> </HierarchicalDataTemplate> </ContextMenu.Resources> </ContextMenu> 
+5
source

I take on MenuItems and MVVM (it was not easy to put icons there)

  public class MenuItemVM { public string Text { get; set; } public List<MenuItemVM> Children { get; set; } public ICommand Command { get; set; } public ImageSource Icon { get; set; } } public IList<MenuItemVM> AddContextMenu { get; set; } 

View:

 <Image x:Key="MenuItemIcon" x:Shared="false" Source="{Binding Icon}" Height="16px" Width="16px"/> <Style x:Key="ContextMenuItemStyle" TargetType="{x:Type MenuItem}"> <Setter Property="MenuItem.Icon" Value="{StaticResource MenuItemIcon}"/> <Setter Property="MenuItem.Command" Value="{Binding Command}" /> <Style.Triggers> <!-- insert a null in ItemsSource if you want a separator --> <DataTrigger Binding="{Binding}" Value="{x:Null}"> <Setter Property="Template" > <Setter.Value> <ControlTemplate> <Separator Style="{StaticResource {x:Static MenuItem.SeparatorStyleKey}}"/> </ControlTemplate> </Setter.Value> </Setter> </DataTrigger> </Style.Triggers> </Style> 

Add context menu to user interface

 <ContextMenu ItemContainerStyle="{StaticResource ContextMenuItemStyle}" ItemsSource="{Binding AddContextMenu}"> <ContextMenu.Resources> <HierarchicalDataTemplate DataType="{x:Type vmp:MenuItemVM}" ItemsSource="{Binding Children}"> <TextBlock Text="{Binding Text}"/> </HierarchicalDataTemplate> </ContextMenu.Resources> </ContextMenu> 
+4
source

Try using ObservableCollection<MenuNode> instead of List<MenuNode> , if you add nodes to the list after the binding is initialized, the collection of items will not be updated unless you shoot INotifyCollectionChanged ( ObservableCollection does this).

+1
source

Source: https://habr.com/ru/post/1347147/


All Articles