WPF 绑定方式动态创建菜单

时间:2024-04-05 12:47:55

第一步:菜单接口定义

  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 绑定方式动态创建菜单

WPF 绑定方式动态创建菜单

相关文章