WPF菜单项模板适用于MVVM

4
我有困难编写XAML表示,以允许绑定到我的背景ViewModel以进行级联菜单。
这是ViewModel的内容:
public class MenuNode
{
  public string Header {get;}
  public List<MenuNode> Items {get;}
}

我所拥有的 XAML 代码如下:
<ContextMenu ItemsSource="{Binding Choices}" >
    <ContextMenu.Resources>
        <DataTemplate DataType="{x:Type vmi:MenuNode}">
            <MenuItem Header="{Binding Header}" ItemsSource="{Binding Items}"/>
        </DataTemplate> 
    </ContextMenu.Resources>
</ContextMenu>

当菜单弹出时,我会看到带有箭头的一级条目(表示应该有子菜单),但当我将鼠标悬停在菜单上时,它不显示子菜单项。 有什么想法吗?

你是否在绑定初始化后添加了项目?也许你需要使用ObservableCollection<MenuNode>而不是List<MenuNode>,这样项目集合就会得到通知。 - Josh G
MenuItem和TabItem项生成的技巧在于填充标题/图标区域。您必须使用ItemContainerStyle来完成它,这很棘手。 - Josh G
3个回答

5

好的,这里是问题:

由于某种原因,您的DataTemplate生成的MenuItems被包装在另一个MenuItem中(结果是嵌套的MenuItems)。子项没有被打开,因为外部的MenuItem没有子项。

解决方案是使用HierarchicalDataTemplate代替:

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

4

我的看法是关于MenuItems和MVVM的(在其中放置图标并不容易)

  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; }

视图:

<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>

在您的用户界面中添加上下文菜单
<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>

1

如果您在绑定初始化后向列表添加节点,那么尝试使用ObservableCollection<MenuNode>而不是List<MenuNode>,除非您触发了INotifyCollectionChanged(ObservableCollection会自动触发)否则项集合将不会被更新。


不是问题,因为对象在绑定之前已经初始化。 - Jose
好的,我想这可能不会成为问题。让我检查一下。乍一看,你的代码看起来很棒。 - Josh G
1
我将把它转换成ObservableCollection<>来看看是否有所不同,也许应该使用HierarchicalTemplate? - Jose
太好了,应该使用HierarchicalDataTemplate。你的XAML看起来应该可以工作,但由于某种原因,模板中的MenuItems被项容器包装在另一个MenuItem中。 - Josh G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接