WPF - 如何使用绑定创建菜单和子菜单
Posted
技术标签:
【中文标题】WPF - 如何使用绑定创建菜单和子菜单【英文标题】:WPF - How can I create menu and submenus using binding 【发布时间】:2014-07-19 10:18:29 【问题描述】:我正在尝试使用绑定创建动态菜单。我的视图模型我有一个包含标题和命令的对象列表。但是,它不起作用。我认为问题出在数据模板中。请参阅下面的代码:
<Menu Background="x:Null" Grid.Row="0" Grid.Column="1" Panel.ZIndex="2" Width="865" Height="85" HorizontalAlignment="Left" ItemsSource="Binding Path=MenuItems">
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="MenuItemViewModel" ItemsSource="Binding Path=MenuItems">
<MenuItem Header="Binding Header" Style="DynamicResource MenuItemStyle1" ItemsSource="Binding Path=MenuItems" Padding="10,12,10,0" Height="44.1" Margin="30,0,0,0" FontWeight="Bold">
<MenuItem.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</MenuItem.ItemsPanel>
</MenuItem>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<MenuItem Header="Binding Header" Style="DynamicResource MenuItemStyle1" Padding="0,8,0,0" Height="38">
</MenuItem>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
</Menu>
结果只显示第一个菜单。子菜单没有显示,但它们在那里,因为有子菜单,箭头打印在菜单标题之后。
有没有人发现装订有问题?或者有什么建议?
仅供参考,MenuItems 是一个 MenuItemViewModel 对象列表,它有一个标题和一个名为 MenuItems 的 MenuItemViewModel 对象(子菜单)列表。
【问题讨论】:
【参考方案1】:如果您像我一样热衷于将 UI 构造保留在 XAML 代码中,经过一些困难,我找到了一种很好的方法来绑定自定义类型的集合以创建菜单项。
在 XAML 中:
<Menu DockPanel.Dock="Top">
<MenuItem Header="SomeHeaderName" ItemsSource="Binding Path=MyCollection">
<MenuItem.ItemsContainerStyle>
<Setter Property="Header" Value="Binding Path=SomeRelevantTextProperty"/>
<EventSetter Event="Click" Handler="SomeMenuItemClickEventHandler"/>
</MenuItem.ItemsContainerStyle>
</MenuItem>
</Menu>
在代码隐藏中:
ObservableCollection<MyClass> MyCollection;
private void SomeMenuItemClickEventHandler(object sender, RoutedEventArgs e)
MenuItem menuItem = sender as MenuItem;
MyClass myClass = menuItem.DataContext as MyClass;
// do something useful!
public class MyClass
public string SomeRelevantTextProperty get;
【讨论】:
【参考方案2】:这很简单,您可以将此代码用于嵌套菜单
ViewModel:TopMenuViewModel.cs
public partial class TopMenuViewModel
public TopMenuViewModel()
TopMenuItems = new ObservableCollection<MenuItem>
new MenuItem
Title = "File",
PageName =typeof(OfficeListView).FullName,
ChildMenuItems=
new MenuItem
Title = "New"
,
new MenuItem
Title = "Open"
,
new MenuItem
Title = "Save"
,
new MenuItem
Title = "Edit"
,
new MenuItem
Title = "Search"
;
视图:TopMenuView.xaml
<Menu IsMainMenu="True" ItemsSource="Binding TopMenuItems">
<Menu.ItemContainerStyle>
<Style TargetType="x:Type MenuItem">
<Setter Property="Header" Value="Binding Title"/>
<Setter Property="ItemsSource" Value="Binding Path=ChildMenuItems"/>
</Style>
</Menu.ItemContainerStyle>
</Menu>
【讨论】:
【参考方案3】:对我来说,它适用于这个简单的模板:
<Menu.ItemContainerStyle>
<Style TargetType="x:Type MenuItem">
<Setter Property="Command" Value="Binding Command" />
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="x:Type local:MenuItemViewModel" ItemsSource="Binding Path=MenuItems">
<TextBlock Text="Binding Header"/>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
这是完整的例子:
MainWindow.xaml:
<Window x:Class="WpfApplication14.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication14"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<Menu DockPanel.Dock="Top" ItemsSource="Binding MenuItems">
<Menu.ItemContainerStyle>
<Style TargetType="x:Type MenuItem">
<Setter Property="Command" Value="Binding Command" />
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="x:Type local:MenuItemViewModel" ItemsSource="Binding Path=MenuItems">
<TextBlock Text="Binding Header"/>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
</Menu>
<Grid>
</Grid>
</DockPanel>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
namespace WpfApplication14
public partial class MainWindow : Window
public ObservableCollection<MenuItemViewModel> MenuItems get; set;
public MainWindow()
InitializeComponent();
MenuItems = new ObservableCollection<MenuItemViewModel>
new MenuItemViewModel Header = "Alpha" ,
new MenuItemViewModel Header = "Beta",
MenuItems = new ObservableCollection<MenuItemViewModel>
new MenuItemViewModel Header = "Beta1" ,
new MenuItemViewModel Header = "Beta2",
MenuItems = new ObservableCollection<MenuItemViewModel>
new MenuItemViewModel Header = "Beta1a" ,
new MenuItemViewModel Header = "Beta1b" ,
new MenuItemViewModel Header = "Beta1c"
,
new MenuItemViewModel Header = "Beta3"
,
new MenuItemViewModel Header = "Gamma"
;
DataContext = this;
public class MenuItemViewModel
private readonly ICommand _command;
public MenuItemViewModel()
_command = new CommandViewModel(Execute);
public string Header get; set;
public ObservableCollection<MenuItemViewModel> MenuItems get; set;
public ICommand Command
get
return _command;
private void Execute()
// (NOTE: In a view model, you normally should not use MessageBox.Show()).
MessageBox.Show("Clicked at " + Header);
public class CommandViewModel : ICommand
private readonly Action _action;
public CommandViewModel(Action action)
_action = action;
public void Execute(object o)
_action();
public bool CanExecute(object o)
return true;
public event EventHandler CanExecuteChanged
add
remove
生成的窗口如下所示:
【讨论】:
谢谢!菜单正在正确构建。但是,如何在 MenuItemViewModel 中绑定命令? 是的,这是可能的。请参阅上面我更新的示例。单击菜单项时,会出现一个带有菜单项标题文本的消息框。 我无法添加Separator
((
以上是关于WPF - 如何使用绑定创建菜单和子菜单的主要内容,如果未能解决你的问题,请参考以下文章
WPF 菜单事件绑定 DataTemplate下button Command事件绑定 DataTemplate遍历实体数据