问题描述
问题总结
目标
导航项是使用节点在视图模型中构建的。
预期和实际结果
这是我迄今为止构建的:
错误
现在我需要将选定的 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
替换为您可以使用的命令实现。
然后,您可以调整样式以将命令绑定到主视图模型上(使用 ElementName
或 RelativeSource
到数据上下文)并绑定单击的 {{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>