wpf 如何实现动态伸缩菜单?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了wpf 如何实现动态伸缩菜单?相关的知识,希望对你有一定的参考价值。

参考技术A expander控件 ,具体见MSDN

WPF动态加载Menu菜单

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

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

  1.  
    <Menu DockPanel.Dock="Top" Name="MenuOptionGroup">
  2.  
    <MenuItem Header="菜单1">
  3.  
    <MenuItem Header="内容1">
  4.  
     
  5.  
    </MenuItem>
  6.  
     
  7.  
    </MenuItem>
  8.  
    <MenuItem Header="菜单2">
  9.  
     
  10.  
    </MenuItem>
  11.  
    </Menu>

  技术图片

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

 

具体思路:

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

 

数据库表设计:

技术图片

 

具体实现方法:

  1.  
    public List<MenuItem> menuItems = new List<MenuItem>();
  2.  
    public MainIndex()
  3.  
    {
  4.  
    InitializeComponent();
  5.  
    SetMenus();
  6.  
    foreach (var item in menuItems)
  7.  
    {
  8.  
    MenuOptionGroup.Items.Add(item);
  9.  
    }
  10.  
    }
  11.  
    private void SetMenus()
  12.  
    {
  13.  
    List<GblMenu> lstMenus = lstGblMenuItem.Where(t => t.PaterId == 0).ToList();
  14.  
    foreach (GblMenu item in lstMenus)
  15.  
    {
  16.  
    MenuItem menuItem = new MenuItem();
  17.  
    menuItem.Header = item.MenuName;
  18.  
    menuItem.Name = item.ItemName;
  19.  
    menuItem = SetMenuItems(menuItem, item.Id);
  20.  
    menuItems.Add(menuItem);
  21.  
    }
  22.  
    }
  23.  
    private MenuItem SetMenuItems(MenuItem menuItem, int PatId)
  24.  
    {
  25.  
    List<GblMenu> lstMenuItems = lstGblMenuItem.Where(t => t.PaterId == PatId).ToList();
  26.  
    foreach (GblMenu item in lstMenuItems)
  27.  
    {
  28.  
    MenuItem menuItems = new MenuItem();
  29.  
    menuItems.Header = item.MenuName;
  30.  
    menuItems.Name = item.ItemName;
  31.  
     
  32.  
    menuItem.Items.Add(menuItems);
  33.  
    if (!lstGblMenuItem.Where(t => t.PaterId == item.Id).ToList().Any())
  34.  
    {
  35.  
    menuItems.Click += MenuItems_Click;
  36.  
    }
  37.  
    SetMenuItems(menuItems, item.Id);
  38.  
    }
  39.  
    return menuItem;
  40.  
    }

效果:

技术图片

 

结语:

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

 

 

出处:https://blog.csdn.net/weixin_42084199/article/details/95042521

========================================================================

WPF动态创建右键菜单

第一步:菜单接口定义

  1.  
    public interface IMenuItem
  2.  
    {
  3.  
    /// <summary>
  4.  
    /// 图标
  5.  
    /// </summary>
  6.  
    string ImageURL { get; set; }
  7.  
     
  8.  
    /// <summary>
  9.  
    /// 名称
  10.  
    /// </summary>
  11.  
    string Caption { get; set; }
  12.  
     
  13.  
    /// <summary>
  14.  
    /// 是否开始分组
  15.  
    /// </summary>
  16.  
    bool IsBeginGroup { get; set; }
  17.  
     
  18.  
    /// <summary>
  19.  
    /// 是否可用
  20.  
    /// </summary>
  21.  
    bool IsEnable { get; set; }
  22.  
     
  23.  
    /// <summary>
  24.  
    /// 是否可见
  25.  
    /// </summary>
  26.  
    bool IsVisible { get; set; }
  27.  
     
  28.  
    /// <summary>
  29.  
    /// 子菜单集合
  30.  
    /// </summary>
  31.  
    List<IMenuItem> SubMenus { get; }
  32.  
     
  33.  
    /// <summary>
  34.  
    /// 执行菜单
  35.  
    /// </summary>
  36.  
    void ExcuteItem(object OperObj);
  37.  
    }

第二步:实现菜单接口

  1.  
    public class MyMeunItem : IMenuItem
  2.  
    {
  3.  
    private Action<object> _action;
  4.  
    public MyMeunItem()
  5.  
    {
  6.  
    m_SubMenus = new List<IMenuItem>();
  7.  
    }
  8.  
     
  9.  
    public MyMeunItem(Action<object> action)
  10.  
    {
  11.  
    _action = action;
  12.  
    m_SubMenus = new List<IMenuItem>();
  13.  
    }
  14.  
     
  15.  
    private string m_Caption = "菜单";
  16.  
    public string Caption
  17.  
    {
  18.  
    get
  19.  
    {
  20.  
    return m_Caption;
  21.  
    }
  22.  
     
  23.  
    set
  24.  
    {
  25.  
    m_Caption = value;
  26.  
    }
  27.  
    }
  28.  
     
  29.  
    public string ImageURL
  30.  
    {
  31.  
    get;
  32.  
    set;
  33.  
    }
  34.  
     
  35.  
    private bool m_IsBeginGroup;
  36.  
    public bool IsBeginGroup
  37.  
    {
  38.  
    get
  39.  
    {
  40.  
    return m_IsBeginGroup;
  41.  
    }
  42.  
     
  43.  
    set
  44.  
    {
  45.  
    m_IsBeginGroup = value;
  46.  
    }
  47.  
    }
  48.  
     
  49.  
    private bool m_IsEnable = true;
  50.  
    public bool IsEnable
  51.  
    {
  52.  
    get
  53.  
    {
  54.  
    return m_IsEnable;
  55.  
    }
  56.  
     
  57.  
    set
  58.  
    {
  59.  
    m_IsEnable = value;
  60.  
    }
  61.  
    }
  62.  
     
  63.  
    private bool m_IsVisible = true;
  64.  
    public bool IsVisible
  65.  
    {
  66.  
    get
  67.  
    {
  68.  
    return m_IsVisible;
  69.  
    }
  70.  
     
  71.  
    set
  72.  
    {
  73.  
    m_IsVisible = value;
  74.  
    }
  75.  
    }
  76.  
     
  77.  
    private List<IMenuItem> m_SubMenus;
  78.  
    public List<IMenuItem> SubMenus
  79.  
    {
  80.  
    get
  81.  
    {
  82.  
    return m_SubMenus;
  83.  
    }
  84.  
    }
  85.  
     
  86.  
    public void ExcuteItem(object OperObj)
  87.  
    {
  88.  
    if (_action != null)
  89.  
    {
  90.  
    _action(OperObj);
  91.  
    }
  92.  
    else
  93.  
    {
  94.  
    MessageBox.Show("MyMenu Do...");
  95.  
    }
  96.  
    }
  97.  
    }

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

  1.  
    public class MyCustomButton : Button
  2.  
    {
  3.  
    static MyCustomButton()
  4.  
    {
  5.  
    }
  6.  
     
  7.  
    public ObservableCollection<IMenuItem> MenuItems
  8.  
    {
  9.  
    get { return (ObservableCollection<IMenuItem>)GetValue(MenuItemsProperty); }
  10.  
    set { SetValue(MenuItemsProperty, value); }
  11.  
    }
  12.  
     
  13.  
    public static readonly DependencyProperty MenuItemsProperty =
  14.  
    DependencyProperty.Register("MenuItems",
  15.  
    typeof(ObservableCollection<IMenuItem>),
  16.  
    typeof(MyCustomButton),
  17.  
    new PropertyMetadata(null, new PropertyChangedCallback(MenuItemsChanged)));
  18.  
     
  19.  
    private static void MenuItemsChanged(DependencyObject dpObj, DependencyPropertyChangedEventArgs e)
  20.  
    {
  21.  
    try
  22.  
    {
  23.  
    MyCustomButton dropButton;
  24.  
    if (dpObj is MyCustomButton)
  25.  
    dropButton = dpObj as MyCustomButton;
  26.  
    else
  27.  
    return;
  28.  
     
  29.  
    dropButton.ContextMenu = new ContextMenu();
  30.  
    ObservableCollection<IMenuItem> colItems = (ObservableCollection<IMenuItem>)dpObj.GetValue(MenuItemsProperty);
  31.  
    if (colItems == null)
  32.  
    return;
  33.  
     
  34.  
    foreach (var item in colItems)
  35.  
    {
  36.  
    MenuItem menuItem = new MenuItem()
  37.  
    {
  38.  
    Header=item.Caption,
  39.  
    Icon = item.ImageURL,
  40.  
    IsEnabled = item.IsEnable,
  41.  
    Visibility = item.IsVisible ? Visibility.Visible : Visibility.Collapsed,
  42.  
    Tag = item
  43.  
    };
  44.  
     
  45.  
    menuItem.Click += (obj, arg) => ((obj as MenuItem).Tag as IMenuItem).ExcuteItem(obj);
  46.  
    // 是否开始分组
  47.  
    if (item.IsBeginGroup)
  48.  
    {
  49.  
    dropButton.ContextMenu.Items.Add(new Separator());
  50.  
    }
  51.  
     
  52.  
    dropButton.ContextMenu.Items.Add(menuItem);
  53.  
    }
  54.  
     
  55.  
    dropButton.ContextMenu.PlacementTarget = dropButton;
  56.  
    dropButton.ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
  57.  
    }
  58.  
    catch (Exception ex)
  59.  
    { }
  60.  
    }
  61.  
    }

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

  1.  
    <Window x:Class="DropDownTest.MainWindow"
  2.  
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.  
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.  
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5.  
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6.  
    xmlns:local="clr-namespace:DropDownTest"
  7.  
    xmlns:uc="clr-namespace:GtMap.Pro.Package.Controls;assembly=GtMap.Pro.Package.Controls"
  8.  
    mc:Ignorable="d"
  9.  
    Title="MainWindow" Height="350" Width="525">
  10.  
    <Window.DataContext>
  11.  
    <local:MainFormVM/>
  12.  
    </Window.DataContext>
  13.  
    <Grid>
  14.  
    <Grid.RowDefinitions>
  15.  
    <RowDefinition Height="40"></RowDefinition>
  16.  
    <RowDefinition Height="40"></RowDefinition>
  17.  
    </Grid.RowDefinitions>
  18.  
    <uc:MyCustomButton Grid.Row="0" MenuItems="{Binding MenuItems}" Content="下拉按钮" Margin="0" Width="60" Height="20"></uc:MyCustomButton>
  19.  
     
  20.  
    </Grid>
  21.  
    </Window>

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

  1.  
    public class MainFormVM : INotifyPropertyChanged
  2.  
    {
  3.  
    public MainFormVM()
  4.  
    {
  5.  
    try
  6.  
    {
  7.  
    m_MenuItems = new ObservableCollection<IMenuItem>();
  8.  
    m_MenuItems.Add(new MyMeunItem() { Caption = "菜单1" });
  9.  
    var item = new MyMeunItem(MenuFunc) { Caption = "菜单2", IsBeginGroup = true };
  10.  
    m_MenuItems.Add(item);
  11.  
    }
  12.  
    catch
  13.  
    {
  14.  
    }
  15.  
    }
  16.  
     
  17.  
    private ObservableCollection<IMenuItem> m_MenuItems;
  18.  
     
  19.  
    public event PropertyChangedEventHandler PropertyChanged;
  20.  
     
  21.  
    public ObservableCollection<IMenuItem> MenuItems
  22.  
    {
  23.  
    get
  24.  
    {
  25.  
    return m_MenuItems;
  26.  
    }
  27.  
     
  28.  
    set
  29.  
    {
  30.  
    m_MenuItems = value;
  31.  
    PropertyChanged(this, new PropertyChangedEventArgs("MenuItems"));
  32.  
    }
  33.  
    }
  34.  
     
  35.  
     
  36.  
    public void MenuFunc(object obj)
  37.  
    {
  38.  
    MessageBox.Show("VM VM VM");
  39.  
    }
  40.  
    }
  41.  
     
  42.  
    public class MyCommand : ICommand
  43.  
    {
  44.  
    Action<object> _action;
  45.  
    public MyCommand(Action<object> action)
  46.  
    {
  47.  
    _action = action;
  48.  
    }
  49.  
     
  50.  
    public event EventHandler CanExecuteChanged;
  51.  
     
  52.  
    public bool CanExecute(object parameter)
  53.  
    {
  54.  
    return true;
  55.  
    }
  56.  
     
  57.  
    public void Execute(object parameter)
  58.  
    {
  59.  
    if (_action != null)
  60.  
    _action(parameter);
  61.  
    }
  62.  
    }

界面效果

技术图片

技术图片

==

WPF 绑定方式动态创建菜单

以上是关于wpf 如何实现动态伸缩菜单?的主要内容,如果未能解决你的问题,请参考以下文章

WPF动态加载Menu菜单

wpf treeview中动态创建的treeViewItem如何用右键触发菜单?

多级伸缩菜单——组合模式

WPF如何实现DataGrid的右键出现选项菜单的功能

WPF左键点按钮弹出菜单如何实现

WPF如何实现DataGrid的右键出现选项菜单的功能