苦苦研究了好长时间,终于搞定mvvm 框架下的 menu 绑定,包括二层和三层MenuItem及其Header、Command和 CommandParameter的绑定,真是好难。
主程序 MainViewModel.cs
public class MainViewModel : ViewModelBase
{
public RelayCommand LoginCommand { get; set; }
public RelayCommand LogoutCommand { get; set; }
public RelayCommand AboutCommand { get; set; }
public RelayCommand QuitWindowCommand { get; set; }
public RelayCommand NewWindowCommand { get; set; }
public RootMenuViewModel TheMenuA { get; set; }
public RootMenuViewModel TheMenuB { get; set; }
public MainViewModel()
{
LoginCommand = new RelayCommand(DoLogin);
AboutCommand = new RelayCommand(DoAbout);
LogoutCommand = new RelayCommand(DoLogout, CanDoLogout);
NewWindowCommand = new RelayCommand(DoNewWindow, CanDoNewWindow);
QuitWindowCommand = new RelayCommand(DoQuit);
TheMenuA = GetMenusA();
TheMenuB = GetMenusB();
TheMenuC = GetMenusC();
}
private RootMenuViewModel GetMenusA()
{
RootMenu RootMenuA = new RootMenu("文件");
RootMenuA.MenuItems = new List<MenuItem>();
MenuItem menuItemA = new MenuItem("新建");
menuItemA.Childs.Add(new ChildItem(menuItemA, "新建1", 1, NewWindowCommand));
menuItemA.Childs.Add(new ChildItem(menuItemA, "新建2", 2, NewWindowCommand));
RootMenuA.MenuItems.Add(menuItemA);
RootMenuA.MenuItems.Add(new MenuItem(""));
RootMenuA.MenuItems.Add(new MenuItem("退出登录", LogoutCommand));
RootMenuA.MenuItems.Add(new MenuItem("Separator"));
RootMenuA.MenuItems.Add(new MenuItem("退出系统", QuitWindowCommand));
RootMenuViewModel rootMenuViewModel = new RootMenuViewModel(RootMenuA);
return rootMenuViewModel;
}
private RootMenuViewModel GetMenusB()
{
ObservableCollection<MenuUseXklx> MenuUseXklx1 = MyApp.DataAccess.GetUseXklxList();
RootMenu RootMenuA = new RootMenu("帮助");
RootMenuA.MenuItems = new List<MenuItem>();
RootMenuA.MenuItems.Add(new MenuItem("关于", AboutCommand));
RootMenuViewModel rootMenuViewModel = new RootMenuViewModel(RootMenuA);
return rootMenuViewModel;
}
//相关命令略
}
相关菜单类字段属性:
public class RootMenu
{
public string RootName { get; set; }
public RelayCommand Command { get; set; }
public List<MenuItem> MenuItems { get; set; }
public RootMenu(string rootName) { RootName = rootName; }
}
public class MenuItem
{
public string MenuItemName { get; set; }
public RelayCommand Command { get; set; }
public List<ChildItem> Childs { get; set; }
public MenuItem(string menuName, RelayCommand command) { MenuItemName = menuName; Command = command; }
public MenuItem(string menuName) { MenuItemName = menuName; }
public MenuItem() { }
}
public class ChildItem
{
public string ChildName { get; set; }
public short Childlx { get; set; }
public RelayCommand Command { get; set; }
public MenuItem MenuItem { get; set; }
public ChildItem(MenuItem menuClass, string childName, short childlx, RelayCommand command) { MenuItem = menuClass; ChildName = childName; Childlx = childlx; Command = command; }
public ChildItem() { }
}
public class SeparatorViewModel : MenuItemViewModel
{
public SeparatorViewModel(MenuItemViewModel parentViewModel)
: base(parentViewModel)
{
}
}
转换类基类:(ViewModelBase代码略)
public class MenuItemViewModel : ViewModelBase
{
/// <summary>
/// Initializes a new instance of the <see cref="MenuItemViewModel"/> class.
/// </summary>
/// <param name="parentViewModel">The parent view model.</param>
public MenuItemViewModel(MenuItemViewModel parentViewModel)
{
ParentViewModel = parentViewModel;
_childMenuItems = new ObservableCollection<MenuItemViewModel>();
}
private ObservableCollection<MenuItemViewModel> _childMenuItems;
/// <summary>
/// Gets the child menu items.
/// </summary>
/// <value>The child menu items.</value>
public ObservableCollection<MenuItemViewModel> Children
{
get
{
return _childMenuItems;
}
}
private string _header;
/// <summary>
/// Gets or sets the header.
/// </summary>
/// <value>The header.</value>
public string Header
{
get
{
return _header;
}
set
{
_header = value; RaisePropertyChanged("Header");
}
}
private short _childlx;
/// <summary>
/// Gets or sets the CommandParameter.
/// </summary>
/// <value>The CommandParameter.</value>
public short Childlx
{
get
{
return _childlx;
}
set
{
_childlx = value; RaisePropertyChanged("Childlx");
}
}
/// <summary>
/// Gets or sets the Command.
/// </summary>
/// <value>The Command.</value>
private RelayCommand command;
public RelayCommand Command
{
get
{
return command;
}
set
{
command = value; RaisePropertyChanged("Command");
}
}
/// <summary>
/// Gets or sets the parent view model.
/// </summary>
/// <value>The parent view model.</value>
public MenuItemViewModel ParentViewModel { get; set; }
public virtual void LoadChildMenuItems()
{
}
Root菜单类:
public class RootMenuViewModel : MenuItemViewModel
{
private RootMenu _rootMenu;
/// <summary>
/// Initializes a new instance of the <see cref="MenuItemViewModel"></see> class.
/// </summary>
/// <param name="parentViewModel">The parent view model.</param>
public RootMenuViewModel(RootMenu rootMenu)
: base(null)
{
_rootMenu = rootMenu;
base.Header = RootName;
base.Command = RootCommand;
if (_rootMenu.MenuItems != null)
LoadChildMenuItems();
}
public string RootName
{
get
{
return _rootMenu.RootName;
}
set
{
_rootMenu.RootName = value; RaisePropertyChanged("RootName");
}
}
public RelayCommand RootCommand
{
get
{
return _rootMenu.Command;
}
set
{
_rootMenu.Command = value; RaisePropertyChanged("RootCommand");
}
}
/// <summary>
/// Loads the child menu items.
/// </summary>
public override void LoadChildMenuItems()
{
_rootMenu.MenuItems.ForEach
(
MenuItem =>
{
if (MenuItem.MenuItemName == string.Empty || MenuItem.MenuItemName == "Separator")
{
SeparatorViewModel separatorViewModel = new SeparatorViewModel(this);
Children.Add(separatorViewModel);
}
else if (MenuItem.MenuItemName != null)
{
MenuClassViewModel childMenuViewModel = new MenuClassViewModel(this, MenuItem);
childMenuViewModel.Header = MenuItem.MenuItemName;
childMenuViewModel.Command = MenuItem.Command;
Children.Add(childMenuViewModel);
}
}
);
}
子菜单类:
public class MenuClassViewModel : MenuItemViewModel
{
private MenuItem _menuClass;
/// <summary>
/// Initializes a new instance of the <see cref="MenuItemViewModel"></see> class.
/// </summary>
/// <param name="parentViewModel">The parent view model.</param>
public MenuClassViewModel(RootMenuViewModel parentViewModel, MenuItem menuClass)
: base(parentViewModel)
{
_menuClass = menuClass;
if (_menuClass.Childs != null)
LoadChildMenuItems();
}
//private string _menuName;
/// <summary>
/// Gets or sets the name of the team.
/// </summary>
/// <value>The name of the team.</value>
public string MenuName
{
get
{
return _menuClass.MenuItemName;
}
set
{
_menuClass.MenuItemName = value; RaisePropertyChanged("MenuName");
}
}
public RelayCommand ItemCommand
{
get
{
return _menuClass.Command;
}
set
{
_menuClass.Command = value; RaisePropertyChanged("ItemCommand");
}
}
public override void LoadChildMenuItems()
{
_menuClass.Childs.ForEach(child =>
{
if (child.ChildName == string.Empty)
{
SeparatorViewModel separatorViewModel = new SeparatorViewModel(this);
Children.Add(separatorViewModel);
}
else
{
ChildMenuViewModel childViewModel = new ChildMenuViewModel(this, child);
childViewModel.Header = child.ChildName;
childViewModel.Childlx = child.Childlx;
childViewModel.Command = child.Command;
Children.Add(childViewModel);
}
});
}
}
三层菜单类:
class ChildMenuViewModel : MenuItemViewModel
{
private ChildItem _child;
/// <summary>
/// Initializes a new instance of the <see cref="MenuItemViewModel"></see> class.
/// </summary>
/// <param name="parentViewModel">The parent view model.</param>
public ChildMenuViewModel(MenuClassViewModel parentViewModel, ChildItem child)
: base(parentViewModel)
{
_child = child;
}
public string ChildName
{
get
{
return _child.ChildName;
}
set
{
_child.ChildName = value; RaisePropertyChanged("ChildName");
}
}
public short ChildLx
{
get
{
return _child.Childlx;
}
set
{
_child.Childlx = value; RaisePropertyChanged("ChildLx");
}
}
public RelayCommand ChildCommand
{
get
{
return _child.Command;
}
set
{
_child.Command = value; RaisePropertyChanged("ChildCommand");
}
}
}
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type vm:MenuItemViewModel}" ItemsSource="{Binding Children}">
<MenuItem Header="{Binding Path=Header}" Command="{Binding Path=Command}" CommandParameter="{Binding Path=Childlx}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type vm:SeparatorViewModel}">
<Separator/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="26*"/>
</Grid.RowDefinitions>
<StackPanel>
<Menu TextBlock.FontSize="14">
<MenuItem ItemsSource="{Binding TheMenuA.Children}" Header="{Binding TheMenuA.Header}"/>
<MenuItem ItemsSource="{Binding TheMenuB.Children}" Header="{Binding TheMenuB.Header}"/>
</Menu>
</StackPanel>
</Grid>