如何获取所选菜单项的内容?

问题描述

问题总结

目标

我的目标是在 WPF 中创建一个导航菜单

导航项是使用节点在视图模型中构建的。

菜单中选中的SubItem显示选中节点的内容

预期和实际结果

这是我迄今为止构建的:

enter image description here

错误

现在我需要将选定的 MenuItem 呈现给 ContentPresenter - 这就是我遇到问题的地方。

我尝试了什么

这是我当前的代码

XAML

<!--Menu-->
<Menu x:Name="NavigationTreeView" IsMainMenu="True" ItemsSource="{Binding Navigation}" Grid.Row="0">
    <Menu.Resources>
        <Style targettype="{x:Type MenuItem}">
            <Setter Property="Header" Value="{Binding Path=Title}" />
            <Setter Property="Template" Value="{StaticResource VsMenutop}" />
        </Style>
        <HierarchicalDataTemplate DataType="{x:Type nav:Pageviewmodel}" ItemsSource="{Binding Children}" />
    </Menu.Resources>
</Menu>

<!--Content-->
<ContentPresenter Grid.Row="1" Content="{Binding ElementName=NavigationTreeView,Path=SelectedItem.Content}" />

这行不通,因为我无法在此处使用以下行将其绑定到 Menu:SelectedItem.Content - 而且 Menu 没有属性 SelectedItem

替代方案

我的替代选择是使用 ListView,因为它包含一个属性 SelectedItem。但我最好使用 Menu

问题

如何从分层数据模板中获取所选项目?

解决方法

Menu 控件没有选定项目的概念,因为它的 MenuItem 本质上是按钮,单击时应执行操作。您可以将 IsCheckable 属性设置为 true 以便能够检查 菜单项,例如 CheckBox,但我想这不适合您的用例在这里。

由于您可能希望根据单击的菜单项显示不同的内容,因此您可以使用一个命令,该命令在您单击 MenuItem 时执行并获取相应的视图模型作为参数并在一个可以被 ContentPresenter 绑定的视图模型。

在包含 Selected 属性的主视图模型中引入 PageViewModel 类型的 Select 属性和 Navigation 命令。该命令设置 Selected 属性。

public class MainViewModel : INotifyPropertyChanged
{
   public MainViewModel()
   {
      Selected = new RelayCommand<PageViewModel>(pageViewModel => Selected = pageViewModel);
      // ...other code.
   }

   public DelegateCommand<PageViewModel> Select { get; }
   
   private PageViewModel _selected;
   public PageViewModel Selected
   {
      get => _selected;
      private set
      {
         if (_selected == value)
            return;
   
         _selected = value;
         OnPropertyChanged();
      }
   }
   
   // ...other code.
}

您可以将 RelayCommand 替换为您可以使用的命令实现。

然后,您可以调整样式以将命令绑定到主视图模型上(使用 ElementNameRelativeSource 到数据上下文)并绑定单击的 {{1 }} 作为命令参数。以这种方式将其传递给命令,该命令将其设置为 MenuItem

Selected

将您的 <Style TargetType="{x:Type MenuItem}"> <Setter Property="Header" Value="{Binding Path=Title}" /> <Setter Property="Template" Value="{StaticResource VsMenuTop}" /> <Setter Property="Command" Value="{Binding DataContext.Select,ElementName=NavigationTreeView}"/> <Setter Property="CommandParameter" Value="{Binding}"/> </Style> Content 绑定到主视图模型上的 ContentPresenter 属性。

Selected
,

Сan 想了很多实现,但并不完全清楚你需要什么。 需要其他详细信息。

SelectedItem(Selector 类的属性)不包含 UI 元素,而是包含集合源元素。 也许您也需要它,而不是 MenuItem?

您没有使用命令,因此您可以使用它们来解决问题。

我使用 BaseInpc and RelayCommand classes 实现了一个简单的代理。

using Simplified;

namespace SelectedItem
{
    public class SelectedItemProxy : BaseInpc
    {
        private object _selectedMenuItem;

        public object SelectedMenuItem { get => _selectedMenuItem; set => Set(ref _selectedMenuItem,value); }

        private RelayCommand _selectItemCommand;
        public RelayCommand SelectItemCommand => _selectItemCommand
            ?? (_selectItemCommand = new RelayCommand(item => SelectedMenuItem = item));
    }
}

使用示例:

<Window x:Class="SelectedItem.SmiExamleWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SelectedItem"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="SmiExamleWindow" Height="450" Width="800">
    <Window.Resources>
        <local:SelectedItemProxy x:Key="proxy"/>
        
    </Window.Resources>
    <Grid>
        <Menu x:Name="NavigationTreeView" IsMainMenu="True" ItemsSource="{Binding Navigation}" Grid.Row="0" VerticalAlignment="Top">
            <Menu.Resources>
                <Style TargetType="{x:Type MenuItem}">
                    <Setter Property="Header" Value="{Binding}"/>
                    <Setter Property="Command" Value="{Binding SelectItemCommand,Source={StaticResource proxy}}"/>
                    <Setter Property="CommandParameter" Value="{Binding}"/>
                </Style>
            </Menu.Resources>
            <sys:String>First</sys:String>
            <sys:String>Second</sys:String>
        </Menu>
        <ContentPresenter Content="{Binding SelectedMenuItem,Source={StaticResource proxy}}" VerticalAlignment="Bottom" />
    </Grid>
</Window>