如何获取所选菜单项的内容?
How to get the Content of selected Menu Item?
问题总结
目标
我的目标是在 WPF 中创建导航菜单。
导航项是使用节点在视图模型中构建的。
选中SubItem
的菜单会显示选中节点的内容
预期和实际结果
这是我到目前为止构建的:
错误
现在我需要将选定的 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}" />
这行不通,因为我无法在此处使用此行将其绑定到菜单:SelectedItem.Content
- 并且菜单没有 属性 SelectedItem
。
备选
我的备选方案是使用 ListView
,因为它包含 属性 SelectedItem
。但最好我想使用 Menu
.
问题
如何从分层数据模板中获取所选项目?
Menu
控件没有选定项的概念,因为它的 MenuItem
本质上是按钮,单击时应执行操作。您可以将 IsCheckable
属性 设置为 true
以便能够 检查 菜单项,例如 CheckBox
,但我猜此处不适合您的用例。
由于您可能希望根据单击的菜单项显示不同的内容,您可以使用命令,当您单击 MenuItem
并获取相应的视图模型作为参数并设置属性 在可以由 ContentPresenter
绑定的视图模型上。
在包含 Navigation
属性的主视图模型中引入类型为 PageViewModel
的 Selected
属性 和 Select
命令。该命令设置 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
替换为您可以随意使用的命令实现。
然后,您可以调整样式以将命令绑定到主视图模型(使用 ElementName
或 RelativeSource
到数据上下文)并绑定单击的视图模型 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>
将 ContentPresenter
的 Content
绑定到主视图模型上的 Selected
属性。
<ContentPresenter Grid.Row="1" Content="{Binding ElementName=NavigationTreeView, Path=Selected}" />
Сan 想到了许多实现,但并不完全清楚您需要什么。
需要更多详细信息。
SelectedItem(选择器class 的属性)不包含UI 元素,而是集合源元素。
也许您也需要它,而不是 MenuItem?
你没有使用命令,所以你可以使用它们来解决问题。
我已经使用 实现了一个简单的代理。
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>
问题总结
目标
我的目标是在 WPF 中创建导航菜单。
导航项是使用节点在视图模型中构建的。
选中SubItem
的菜单会显示选中节点的内容
预期和实际结果
这是我到目前为止构建的:
错误
现在我需要将选定的 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}" />
这行不通,因为我无法在此处使用此行将其绑定到菜单:SelectedItem.Content
- 并且菜单没有 属性 SelectedItem
。
备选
我的备选方案是使用 ListView
,因为它包含 属性 SelectedItem
。但最好我想使用 Menu
.
问题
如何从分层数据模板中获取所选项目?
Menu
控件没有选定项的概念,因为它的 MenuItem
本质上是按钮,单击时应执行操作。您可以将 IsCheckable
属性 设置为 true
以便能够 检查 菜单项,例如 CheckBox
,但我猜此处不适合您的用例。
由于您可能希望根据单击的菜单项显示不同的内容,您可以使用命令,当您单击 MenuItem
并获取相应的视图模型作为参数并设置属性 在可以由 ContentPresenter
绑定的视图模型上。
在包含 Navigation
属性的主视图模型中引入类型为 PageViewModel
的 Selected
属性 和 Select
命令。该命令设置 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
替换为您可以随意使用的命令实现。
然后,您可以调整样式以将命令绑定到主视图模型(使用 ElementName
或 RelativeSource
到数据上下文)并绑定单击的视图模型 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>
将 ContentPresenter
的 Content
绑定到主视图模型上的 Selected
属性。
<ContentPresenter Grid.Row="1" Content="{Binding ElementName=NavigationTreeView, Path=Selected}" />
Сan 想到了许多实现,但并不完全清楚您需要什么。 需要更多详细信息。
SelectedItem(选择器class 的属性)不包含UI 元素,而是集合源元素。 也许您也需要它,而不是 MenuItem?
你没有使用命令,所以你可以使用它们来解决问题。
我已经使用
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>