有一个项目动态加载wpf的菜单控件可以非常有效的做到更具用户权限显示或控制MenuItem菜单,如何实现这种功能,其实也非常简单。

  首先需要了解Wpf的menu菜单控件,她的结构其实也非常简单



<Menu DockPanel.Dock="Top" Name="MenuOptionGroup">
<MenuItem Header="菜单1">
<MenuItem Header="内容1">
</MenuItem>
</MenuItem>
<MenuItem Header="菜单2">
</MenuItem>
</Menu>


 

  WPF动态加载Menu菜单_microsoft

这是其最基本的结构,menu是其菜单主体,menu下面有menuitem,menuitem可以无限的放入menuitem.

 

具体思路:

获取需要的显示菜单数据(数据需要拥有父id字段,就是这个menitem的上一级menuitem的id),通过先查询出menuitem数据的父id字段为0的menuitem的数据(就是menuitem没有上一级菜单的菜单项目)Add加载menuitem 到menu。然后继续拿到此的id来做查询出是否还有父id的数为此id的,如果有就继续下去,没有则给menuitem 注册一个click事件,用于点击菜单项目做相应的操作。

 

数据库表设计:

WPF动态加载Menu菜单_microsoft_02

 

具体实现方法:



public List<MenuItem> menuItems = new List<MenuItem>();
public MainIndex()
{
InitializeComponent();
SetMenus();
foreach (var item in menuItems)
{
MenuOptionGroup.Items.Add(item);
}
}
private void SetMenus()
{
List<GblMenu> lstMenus = lstGblMenuItem.Where(t => t.PaterId == 0).ToList();
foreach (GblMenu item in lstMenus)
{
MenuItem menuItem = new MenuItem();
menuItem.Header = item.MenuName;
menuItem.Name = item.ItemName;
menuItem = SetMenuItems(menuItem, item.Id);
menuItems.Add(menuItem);
}
}
private MenuItem SetMenuItems(MenuItem menuItem, int PatId)
{
List<GblMenu> lstMenuItems = lstGblMenuItem.Where(t => t.PaterId == PatId).ToList();
foreach (GblMenu item in lstMenuItems)
{
MenuItem menuItems = new MenuItem();
menuItems.Header = item.MenuName;
menuItems.Name = item.ItemName;

menuItem.Items.Add(menuItems);
if (!lstGblMenuItem.Where(t => t.PaterId == item.Id).ToList().Any())
{
menuItems.Click += MenuItems_Click;
}
SetMenuItems(menuItems, item.Id);
}
return menuItem;
}


 

效果:

WPF动态加载Menu菜单_xml_03

结语:

其实这只是其中一个方法,且这种方法也适用与Winform,都是同一个套路。


 WPF动态创建右键菜单



第一步:菜单接口定义



public interface IMenuItem
{
/// <summary>
/// 图标
/// </summary>
string ImageURL { get; set; }

/// <summary>
/// 名称
/// </summary>
string Caption { get; set; }

/// <summary>
/// 是否开始分组
/// </summary>
bool IsBeginGroup { get; set; }

/// <summary>
/// 是否可用
/// </summary>
bool IsEnable { get; set; }

/// <summary>
/// 是否可见
/// </summary>
bool IsVisible { get; set; }

/// <summary>
/// 子菜单集合
/// </summary>
List<IMenuItem> SubMenus { get; }

/// <summary>
/// 执行菜单
/// </summary>
void ExcuteItem(object OperObj);
}


 

第二步:实现菜单接口



public class MyMeunItem : IMenuItem
{
private Action<object> _action;
public MyMeunItem()
{
m_SubMenus = new List<IMenuItem>();
}

public MyMeunItem(Action<object> action)
{
_action = action;
m_SubMenus = new List<IMenuItem>();
}

private string m_Caption = "菜单";
public string Caption
{
get
{
return m_Caption;
}

set
{
m_Caption = value;
}
}

public string ImageURL
{
get;
set;
}

private bool m_IsBeginGroup;
public bool IsBeginGroup
{
get
{
return m_IsBeginGroup;
}

set
{
m_IsBeginGroup = value;
}
}

private bool m_IsEnable = true;
public bool IsEnable
{
get
{
return m_IsEnable;
}

set
{
m_IsEnable = value;
}
}

private bool m_IsVisible = true;
public bool IsVisible
{
get
{
return m_IsVisible;
}

set
{
m_IsVisible = value;
}
}

private List<IMenuItem> m_SubMenus;
public List<IMenuItem> SubMenus
{
get
{
return m_SubMenus;
}
}

public void ExcuteItem(object OperObj)
{
if (_action != null)
{
_action(OperObj);
}
else
{
MessageBox.Show("MyMenu Do...");
}
}
}


 

第三步:自定义控件,添加菜单依赖属性(以button为例)



public class MyCustomButton : Button
{
static MyCustomButton()
{
}

public ObservableCollection<IMenuItem> MenuItems
{
get { return (ObservableCollection<IMenuItem>)GetValue(MenuItemsProperty); }
set { SetValue(MenuItemsProperty, value); }
}

public static readonly DependencyProperty MenuItemsProperty =
DependencyProperty.Register("MenuItems",
typeof(ObservableCollection<IMenuItem>),
typeof(MyCustomButton),
new PropertyMetadata(null, new PropertyChangedCallback(MenuItemsChanged)));

private static void MenuItemsChanged(DependencyObject dpObj, DependencyPropertyChangedEventArgs e)
{
try
{
MyCustomButton dropButton;
if (dpObj is MyCustomButton)
dropButton = dpObj as MyCustomButton;
else
return;

dropButton.ContextMenu = new ContextMenu();
ObservableCollection<IMenuItem> colItems = (ObservableCollection<IMenuItem>)dpObj.GetValue(MenuItemsProperty);
if (colItems == null)
return;

foreach (var item in colItems)
{
MenuItem menuItem = new MenuItem()
{
Header=item.Caption,
Icon = item.ImageURL,
IsEnabled = item.IsEnable,
Visibility = item.IsVisible ? Visibility.Visible : Visibility.Collapsed,
Tag = item
};

menuItem.Click += (obj, arg) => ((obj as MenuItem).Tag as IMenuItem).ExcuteItem(obj);
// 是否开始分组
if (item.IsBeginGroup)
{
dropButton.ContextMenu.Items.Add(new Separator());
}

dropButton.ContextMenu.Items.Add(menuItem);
}

dropButton.ContextMenu.PlacementTarget = dropButton;
dropButton.ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
}
catch (Exception ex)
{ }
}
}


 

第四步:XAML中添加该自定义按钮



<Window x:Class="DropDownTest.MainWindow"
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:DropDownTest"
xmlns:uc="clr-namespace:GtMap.Pro.Package.Controls;assembly=GtMap.Pro.Package.Controls"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainFormVM/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<uc:MyCustomButton Grid.Row="0" MenuItems="{Binding MenuItems}" Content="下拉按钮" Margin="0" Width="60" Height="20"></uc:MyCustomButton>

</Grid>
</Window>


 

第五步:ViewModel编写,添加菜单项



public class MainFormVM : INotifyPropertyChanged
{
public MainFormVM()
{
try
{
m_MenuItems = new ObservableCollection<IMenuItem>();
m_MenuItems.Add(new MyMeunItem() { Caption = "菜单1" });
var item = new MyMeunItem(MenuFunc) { Caption = "菜单2", IsBeginGroup = true };
m_MenuItems.Add(item);
}
catch
{
}
}

private ObservableCollection<IMenuItem> m_MenuItems;

public event PropertyChangedEventHandler PropertyChanged;

public ObservableCollection<IMenuItem> MenuItems
{
get
{
return m_MenuItems;
}

set
{
m_MenuItems = value;
PropertyChanged(this, new PropertyChangedEventArgs("MenuItems"));
}
}


public void MenuFunc(object obj)
{
MessageBox.Show("VM VM VM");
}
}

public class MyCommand : ICommand
{
Action<object> _action;
public MyCommand(Action<object> action)
{
_action = action;
}

public event EventHandler CanExecuteChanged;

public bool CanExecute(object parameter)
{
return true;
}

public void Execute(object parameter)
{
if (_action != null)
_action(parameter);
}
}


 

界面效果

WPF动态加载Menu菜单_菜单项_04

WPF动态加载Menu菜单_xml_05


WPF后台动态生成右键菜单



#region 循环生成右键菜单
private ContextMenu ContextMenus(Dictionary<string, RoutedEventHandler> list)
{
ContextMenu cm = new ContextMenu();
Style style = (Style)this.FindResource("ContextMenu"); //定义前台显示模板
cm.Style = style;
foreach (var dc in list)
{
MenuItem menu = new MenuItem();
menu.Style = (Style)this.FindResource("JjxyMenuItem");
menu.Header = dc.Key;
menu.Click += dc.Value;
cm.Items.Add(menu);
}


return cm;
}
#endregion


需要右键菜单的地方使用:



Dictionary<string, RoutedEventHandler> dist = new Dictionary<string, RoutedEventHandler>();
//添加右键菜单项,包括名称和事件
dist.Add("添加", add_Click);
dist.Add("修改", edit_Click);
dist.Add("删除", del_Click);
dist.Add("导出", putout_Click);
dgrid.ContextMenu = ContextMenus(dist);


 

添加即可,dgrid为DataGrid实例对象,使用字典,string为菜单名,RoutedEventHandler为菜单事件。