(十三)c#Winform自定义控件-导航菜单

准备工作

有时候我们需要左侧的导航菜单,那么来整一个吧

先来分析分析,导航菜单一般分为2级或多级,如果是多级的话 用前面的treeview更合适,这里只做2级,为了父子节点样式更方便控制,我们分别实现父子节点。

为了更加的Open,我们使用接口来定义一下

开始

定义一个节点数据绑定实体

[Serializable]
    public class MenuItemEntity
    {
        /// <summary>
        /// 键
        /// </summary>
        public string Key { get; set; }
        /// <summary>
        /// 文字
        /// </summary>
        public string Text { get; set; }
        /// <summary>
        /// 子节点
        /// </summary>
        public List<MenuItemEntity> Childrens { get; set; }
        /// <summary>
        /// 自定义数据源,一般用于扩展展示,比如定义节点图片等
        /// </summary>
        public object DataSource { get; set; }

    }

再定义一个接口来约束

public interface IMenuItem
    {
        event EventHandler SelectedItem;
        MenuItemEntity DataSource { get; set; }
        /// <summary>
        /// 设置样式
        /// </summary>
        /// <param name="styles">key:属性名称,value:属性值</param>
        void SetStyle(Dictionary<string, object> styles);
        /// <summary>
        /// 设置选中样式
        /// </summary>
        /// <param name="blnSelected">是否选中</param>
        void SetSelectedStyle(bool blnSelected);
    }

首先看父节点定义,添加一个用户控件,命名UCMenuParentItem,并且实现接口IMenuItem

public event EventHandler SelectedItem;

        private MenuItemEntity m_dataSource;
        public MenuItemEntity DataSource
        {
            get
            {
                return m_dataSource;
            }
            set
            {
                m_dataSource = value;
                if (value != null)
                {
                    lblTitle.Text = value.Text;
                }
            }
        }
 public void SetStyle(Dictionary<string, object> styles)
        {
            Type t = this.GetType();
            foreach (var item in styles)
            {
                var pro = t.GetProperty(item.Key);
                if (pro != null && pro.CanWrite)
                {
                    try
                    {
                        pro.SetValue(this, item.Value, null);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("菜单元素设置样式异常", ex);
                    }
                }
            }
        }

        public void SetSelectedStyle(bool blnSelected)
        {
            if (blnSelected)
            {
                this.lblTitle.Image = Properties.Resources.sanjiao1;
            }
            else
            {
                this.lblTitle.Image = Properties.Resources.sanjiao2;
            }
        }

然后处理下点击事件

lblTitle.MouseDown += lblTitle_MouseDown;

  void lblTitle_MouseDown(object sender, MouseEventArgs e)
        {
            if (SelectedItem != null)
            {
                SelectedItem(this, e);
            }
        }

这样就完事了,看下完整代码

// 版权所有  黄正辉  交流群:568015492   QQ:623128629
// 文件名称:UCMenuParentItem.cs
// 创建日期:2019-08-15 16:02:35
// 功能描述:Menu
// 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace HZH_Controls.Controls
{
    /// <summary>
    /// 父类节点
    /// </summary>
    [ToolboxItem(false)]
    public partial class UCMenuParentItem : UserControl, IMenuItem
    {
        public event EventHandler SelectedItem;

        private MenuItemEntity m_dataSource;
        public MenuItemEntity DataSource
        {
            get
            {
                return m_dataSource;
            }
            set
            {
                m_dataSource = value;
                if (value != null)
                {
                    lblTitle.Text = value.Text;
                }
            }
        }

        public UCMenuParentItem()
        {
            InitializeComponent();
            lblTitle.MouseDown += lblTitle_MouseDown;
        }

        public void SetStyle(Dictionary<string, object> styles)
        {
            Type t = this.GetType();
            foreach (var item in styles)
            {
                var pro = t.GetProperty(item.Key);
                if (pro != null && pro.CanWrite)
                {
                    try
                    {
                        pro.SetValue(this, item.Value, null);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("菜单元素设置样式异常", ex);
                    }
                }
            }
        }

        public void SetSelectedStyle(bool blnSelected)
        {
            if (blnSelected)
            {
                this.lblTitle.Image = Properties.Resources.sanjiao1;
            }
            else
            {
                this.lblTitle.Image = Properties.Resources.sanjiao2;
            }
        }

        void lblTitle_MouseDown(object sender, MouseEventArgs e)
        {
            if (SelectedItem != null)
            {
                SelectedItem(this, e);
            }
        }
    }
}
namespace HZH_Controls.Controls
{
    partial class UCMenuParentItem
    {
        /// <summary> 
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 组件设计器生成的代码

        /// <summary> 
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.ucSplitLine_H1 = new HZH_Controls.Controls.UCSplitLine_H();
            this.lblTitle = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // ucSplitLine_H1
            // 
            this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(30)))), ((int)(((byte)(39)))));
            this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.ucSplitLine_H1.Location = new System.Drawing.Point(0, 59);
            this.ucSplitLine_H1.Name = "ucSplitLine_H1";
            this.ucSplitLine_H1.Size = new System.Drawing.Size(200, 1);
            this.ucSplitLine_H1.TabIndex = 0;
            this.ucSplitLine_H1.TabStop = false;
            // 
            // lblTitle
            // 
            this.lblTitle.Dock = System.Windows.Forms.DockStyle.Fill;
            this.lblTitle.ForeColor = System.Drawing.Color.White;
            this.lblTitle.Image = global::HZH_Controls.Properties.Resources.sanjiao2;
            this.lblTitle.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
            this.lblTitle.Location = new System.Drawing.Point(0, 0);
            this.lblTitle.Name = "lblTitle";
            this.lblTitle.Size = new System.Drawing.Size(200, 59);
            this.lblTitle.TabIndex = 1;
            this.lblTitle.Text = "父项";
            this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            // 
            // UCMenuParentItem
            // 
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(43)))), ((int)(((byte)(54)))));
            this.Controls.Add(this.lblTitle);
            this.Controls.Add(this.ucSplitLine_H1);
            this.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.Name = "UCMenuParentItem";
            this.Size = new System.Drawing.Size(200, 60);
            this.ResumeLayout(false);

        }

        #endregion

        private UCSplitLine_H ucSplitLine_H1;
        private System.Windows.Forms.Label lblTitle;
    }
}

设计效果就是这样子的了

父节点弄好了,下面就是子节点了

添加用户控件,命名UCMenuChildrenItem,实现接口IMenuItem

public event EventHandler SelectedItem;

        private MenuItemEntity m_dataSource;
        public MenuItemEntity DataSource
        {
            get
            {
                return m_dataSource;
            }
            set
            {
                m_dataSource = value;
                if (value != null)
                {
                    lblTitle.Text = value.Text;
                }
            }
        }

 public void SetStyle(Dictionary<string, object> styles)
        {
            Type t = this.GetType();
            foreach (var item in styles)
            {
                var pro = t.GetProperty(item.Key);
                if (pro != null && pro.CanWrite)
                {
                    try
                    {
                        pro.SetValue(this, item.Value, null);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("菜单元素设置样式异常", ex);
                    }
                }
            }
        }

处理下点击事件

this.lblTitle.MouseDown += lblTitle_MouseDown;

       void lblTitle_MouseDown(object sender, MouseEventArgs e)
        {
            if (SelectedItem != null)
            {
                SelectedItem(this, null);
            }
        }

这样就完成了,看下完整代码

// 版权所有  黄正辉  交流群:568015492   QQ:623128629
// 文件名称:UCMenuChildrenItem.cs
// 创建日期:2019-08-15 16:02:26
// 功能描述:Menu
// 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace HZH_Controls.Controls
{
    /// <summary>
    /// 子类节点
    /// </summary>
    [ToolboxItem(false)]
    public partial class UCMenuChildrenItem : UserControl, IMenuItem
    {
        public event EventHandler SelectedItem;

        private MenuItemEntity m_dataSource;
        public MenuItemEntity DataSource
        {
            get
            {
                return m_dataSource;
            }
            set
            {
                m_dataSource = value;
                if (value != null)
                {
                    lblTitle.Text = value.Text;
                }
            }
        }
        public UCMenuChildrenItem()
        {
            InitializeComponent();
            this.lblTitle.MouseDown += lblTitle_MouseDown;
        }

        void lblTitle_MouseDown(object sender, MouseEventArgs e)
        {
            if (SelectedItem != null)
            {
                SelectedItem(this, null);
            }
        }

        public void SetStyle(Dictionary<string, object> styles)
        {
            Type t = this.GetType();
            foreach (var item in styles)
            {
                var pro = t.GetProperty(item.Key);
                if (pro != null && pro.CanWrite)
                {
                    try
                    {
                        pro.SetValue(this, item.Value, null);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("菜单元素设置样式异常", ex);
                    }
                }
            }
        }

        public void SetSelectedStyle(bool blnSelected)
        {

        }
    }
}
namespace HZH_Controls.Controls
{
    partial class UCMenuChildrenItem
    {
        /// <summary> 
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 组件设计器生成的代码

        /// <summary> 
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.ucSplitLine_H1 = new HZH_Controls.Controls.UCSplitLine_H();
            this.lblTitle = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // ucSplitLine_H1
            // 
            this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(43)))), ((int)(((byte)(54)))));
            this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.ucSplitLine_H1.Location = new System.Drawing.Point(0, 59);
            this.ucSplitLine_H1.Name = "ucSplitLine_H1";
            this.ucSplitLine_H1.Size = new System.Drawing.Size(200, 1);
            this.ucSplitLine_H1.TabIndex = 0;
            this.ucSplitLine_H1.TabStop = false;
            // 
            // lblTitle
            // 
            this.lblTitle.Dock = System.Windows.Forms.DockStyle.Fill;
            this.lblTitle.Font = new System.Drawing.Font("微软雅黑", 12F);
            this.lblTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(145)))), ((int)(((byte)(152)))), ((int)(((byte)(170)))));
            this.lblTitle.Location = new System.Drawing.Point(0, 0);
            this.lblTitle.Name = "lblTitle";
            this.lblTitle.Size = new System.Drawing.Size(200, 59);
            this.lblTitle.TabIndex = 1;
            this.lblTitle.Text = "子项";
            this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            // 
            // UCMenuChildrenItem
            // 
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(30)))), ((int)(((byte)(39)))));
            this.Controls.Add(this.lblTitle);
            this.Controls.Add(this.ucSplitLine_H1);
            this.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.Name = "UCMenuChildrenItem";
            this.Size = new System.Drawing.Size(200, 60);
            this.ResumeLayout(false);

        }

        #endregion

        private UCSplitLine_H ucSplitLine_H1;
        private System.Windows.Forms.Label lblTitle;

    }
}

设计效果是这样子的

你们有没有发现,父节点和子节点代码非常的相似呢?是的,基本上都是一样的,他们都实现了接口IMenuItem,

那既然如此为什么还要分为2个,这不是代码冗余了吗?这么做的好处就是你可以更方便的控制节点的设计样式,假如有一天,子节点你不想用文字了,你先够用图片呢?

 到此,节点定义已经完成了,剩下的就是处理列表了,继续往下看吧。

定义一个用户控件,命名UCMenu

首先定义一个枚举

public enum MenuStyle
    {
        /// <summary>
        /// 平铺
        /// </summary>
        Fill = 1,
        /// <summary>
        /// 顶部对齐
        /// </summary>
        Top = 2,
    }

这个枚举的作用就是改变样式,默认是Fill,也就是子节点面板填充铺满,选中父节点上面的兄弟节点顶端对齐,下面的兄弟节点低端对齐,当父节点较多时候就会出现子节点无法显示的问题,这个时候使用Top就可以了,所有父节点顶端对齐

先看下有哪些属性

/// <summary>
        /// 选中项事件
        /// </summary>
        public event EventHandler SelectedItem;
        private Type m_parentItemType = typeof(UCMenuParentItem);
        /// <summary>
        /// 父类节点类型
        /// </summary>
        public Type ParentItemType
        {
            get { return m_parentItemType; }
            set
            {
                if (value == null)
                    return;
                if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
                    throw new Exception("节点控件没有实现IMenuItem接口");
                m_parentItemType = value;

            }
        }

        private Type m_childrenItemType = typeof(UCMenuChildrenItem);
        /// <summary>
        /// 子类节点类型
        /// </summary>
        public Type ChildrenItemType
        {
            get { return m_childrenItemType; }
            set
            {
                if (value == null)
                    return;
                if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
                    throw new Exception("节点控件没有实现IMenuItem接口");
                m_childrenItemType = value;
            }
        }

        private Dictionary<string, object> m_parentItemStyles;
        /// <summary>
        /// 父类节点样式设置,key:属性名称,value:属性值
        /// </summary>
        public Dictionary<string, object> ParentItemStyles
        {
            get { return m_parentItemStyles; }
            set { m_parentItemStyles = value; }
        }

        private Dictionary<string, object> m_childrenItemStyles;
        /// <summary>
        /// 子类节点样式设置,key:属性名称,value:属性值
        /// </summary>
        public Dictionary<string, object> ChildrenItemStyles
        {
            get { return m_childrenItemStyles; }
            set { m_childrenItemStyles = value; }
        }

        private List<MenuItemEntity> m_dataSource;
        /// <summary>
        /// 数据源
        /// </summary>
        public List<MenuItemEntity> DataSource
        {
            get { return m_dataSource; }
            set
            {
                m_dataSource = value;

                ReloadItems();
            }
        }
        private bool m_isShowFirstItem = true;
        /// <summary>
        /// 是否自动展开第一个节点
        /// </summary>
        public bool IsShowFirstItem
        {
            get { return m_isShowFirstItem; }
            set { m_isShowFirstItem = value; }
        }

        private MenuStyle m_menuStyle = MenuStyle.Fill;
        /// <summary>
        /// 菜单样式
        /// </summary>
        public MenuStyle MenuStyle
        {
            get { return m_menuStyle; }
            set { m_menuStyle = value; }
        }

        private List<Control> m_lstParentItems = new List<Control>();

        private IMenuItem m_selectParentItem = null;
        private IMenuItem m_selectChildrenItem = null;

        private Panel m_panChildren = null;

数据源改变时需要重新加载

private void ReloadItems()
        {
            try
            {
                ControlHelper.FreezeControl(this, true);
                this.Controls.Clear();
                m_lstParentItems.Clear();
                if (m_dataSource != null && m_dataSource.Count > 0)
                {
                    foreach (var parent in m_dataSource)
                    {
                        IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_parentItemType);
                        parentItem.DataSource = parent;
                        if (m_parentItemStyles != null)
                            parentItem.SetStyle(m_parentItemStyles);
                        parentItem.SelectedItem += parentItem_SelectedItem;
                        Control c = parentItem as Control;
                        c.Dock = DockStyle.Top;
                        this.Controls.Add(c);
                        this.Controls.SetChildIndex(c, 0);
                        m_lstParentItems.Add(c);
                    }
                }
                m_panChildren = new Panel();
                if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
                {
                    m_panChildren.Dock = DockStyle.Fill;
                    m_panChildren.Height = 0;
                }
                else
                {
                    m_panChildren.Dock = DockStyle.Top;
                    m_panChildren.Height = 0;
                }
                m_panChildren.AutoScroll = true;
                this.Controls.Add(m_panChildren);
            }
            finally
            {
                ControlHelper.FreezeControl(this, false);
            }

            if (m_isShowFirstItem && m_lstParentItems != null && m_lstParentItems.Count > 0)
            {
                parentItem_SelectedItem(m_lstParentItems[0], null);
            }
        }

选中父节点时候加载子节点

void parentItem_SelectedItem(object sender, EventArgs e)
        {
            this.FindForm().ActiveControl = this;
            IMenuItem item = sender as IMenuItem;
            if (m_lstParentItems.Contains(sender as Control))
            {
                if (m_selectParentItem != item)
                {
                    if (m_selectParentItem != null)
                    {
                        m_selectParentItem.SetSelectedStyle(false);
                    }
                    m_selectParentItem = item;
                    m_selectParentItem.SetSelectedStyle(true);
                    SetChildrenControl(m_selectParentItem);
                }
                else
                {
                    m_selectParentItem.SetSelectedStyle(false);
                    m_selectParentItem = null;
                    SetChildrenControl(m_selectParentItem, false);
                }
            }
            else if (m_panChildren.Controls.Contains(sender as Control))
            {
                if (m_selectChildrenItem != item)
                {
                    if (m_selectChildrenItem != null)
                    {
                        m_selectChildrenItem.SetSelectedStyle(false);
                    }
                    m_selectChildrenItem = item;
                    m_selectChildrenItem.SetSelectedStyle(true);
                }
            }
            if (SelectedItem != null)
            {
                SelectedItem(sender, e);
            }
        }

        private void SetChildrenControl(IMenuItem menuitem, bool blnChildren = true)
        {
            try
            {
                ControlHelper.FreezeControl(this, true);
                if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
                {
                    if (blnChildren)
                    {
                        Control cMenu = menuitem as Control;
                        int index = m_lstParentItems.IndexOf(cMenu);
                        for (int i = 0; i <= index; i++)
                        {
                            m_lstParentItems[i].Dock = DockStyle.Top;
                            this.Controls.SetChildIndex(m_lstParentItems[i], 1);
                        }
                        for (int i = index + 1; i < m_lstParentItems.Count; i++)
                        {
                            m_lstParentItems[i].Dock = DockStyle.Bottom;
                            this.Controls.SetChildIndex(m_lstParentItems[i], m_lstParentItems.Count);
                        }
                        m_panChildren.Controls.Clear();
                        int intItemHeigth = 0;
                        foreach (var item in menuitem.DataSource.Childrens)
                        {
                            IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
                            parentItem.DataSource = item;
                            if (m_childrenItemStyles != null)
                                parentItem.SetStyle(m_childrenItemStyles);
                            parentItem.SelectedItem += parentItem_SelectedItem;
                            Control c = parentItem as Control;
                            if (intItemHeigth == 0)
                                intItemHeigth = c.Height;
                            c.Dock = DockStyle.Top;
                            m_panChildren.Controls.Add(c);
                            m_panChildren.Controls.SetChildIndex(c, 0);
                        }
                        //m_panChildren.MinimumSize = new Size(0, menuitem.DataSource.Childrens.Count * intItemHeigth);
                    }
                    else
                    {
                        m_panChildren.Controls.Clear();
                        foreach (var item in m_lstParentItems)
                        {
                            item.Dock = DockStyle.Top;
                            this.Controls.SetChildIndex(item, 1);
                        }
                    }
                }
                else
                {
                    if (blnChildren)
                    {
                        Control cMenu = menuitem as Control;
                        int index = m_lstParentItems.IndexOf(cMenu);
                        this.Controls.SetChildIndex(m_panChildren, m_lstParentItems.Count - index - 1);
                        m_panChildren.Controls.Clear();
                        int intItemHeigth = 0;
                        foreach (var item in menuitem.DataSource.Childrens)
                        {
                            IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
                            parentItem.DataSource = item;
                            if (m_childrenItemStyles != null)
                                parentItem.SetStyle(m_childrenItemStyles);
                            parentItem.SelectedItem += parentItem_SelectedItem;
                            Control c = parentItem as Control;
                            if (intItemHeigth == 0)
                                intItemHeigth = c.Height;
                            c.Dock = DockStyle.Top;
                            m_panChildren.Controls.Add(c);
                            m_panChildren.Controls.SetChildIndex(c, 0);
                        }
                        m_panChildren.Height = menuitem.DataSource.Childrens.Count * intItemHeigth;
                    }
                    else
                    {
                        m_panChildren.Controls.Clear();
                        m_panChildren.Height = 0;
                    }
                }
            }
            finally
            {
                ControlHelper.FreezeControl(this, false);
            }
        }

代码就这么多,看下完整代码

// 版权所有  黄正辉  交流群:568015492   QQ:623128629
// 文件名称:UCMenu.cs
// 创建日期:2019-08-15 16:02:22
// 功能描述:Menu
// 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace HZH_Controls.Controls
{
    public partial class UCMenu : UserControl
    {
        /// <summary>
        /// 选中项事件
        /// </summary>
        public event EventHandler SelectedItem;
        private Type m_parentItemType = typeof(UCMenuParentItem);
        /// <summary>
        /// 父类节点类型
        /// </summary>
        public Type ParentItemType
        {
            get { return m_parentItemType; }
            set
            {
                if (value == null)
                    return;
                if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
                    throw new Exception("节点控件没有实现IMenuItem接口");
                m_parentItemType = value;

            }
        }

        private Type m_childrenItemType = typeof(UCMenuChildrenItem);
        /// <summary>
        /// 子类节点类型
        /// </summary>
        public Type ChildrenItemType
        {
            get { return m_childrenItemType; }
            set
            {
                if (value == null)
                    return;
                if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
                    throw new Exception("节点控件没有实现IMenuItem接口");
                m_childrenItemType = value;
            }
        }

        private Dictionary<string, object> m_parentItemStyles;
        /// <summary>
        /// 父类节点样式设置,key:属性名称,value:属性值
        /// </summary>
        public Dictionary<string, object> ParentItemStyles
        {
            get { return m_parentItemStyles; }
            set { m_parentItemStyles = value; }
        }

        private Dictionary<string, object> m_childrenItemStyles;
        /// <summary>
        /// 子类节点样式设置,key:属性名称,value:属性值
        /// </summary>
        public Dictionary<string, object> ChildrenItemStyles
        {
            get { return m_childrenItemStyles; }
            set { m_childrenItemStyles = value; }
        }

        private List<MenuItemEntity> m_dataSource;
        /// <summary>
        /// 数据源
        /// </summary>
        public List<MenuItemEntity> DataSource
        {
            get { return m_dataSource; }
            set
            {
                m_dataSource = value;

                ReloadItems();
            }
        }
        private bool m_isShowFirstItem = true;
        /// <summary>
        /// 是否自动展开第一个节点
        /// </summary>
        public bool IsShowFirstItem
        {
            get { return m_isShowFirstItem; }
            set { m_isShowFirstItem = value; }
        }

        private MenuStyle m_menuStyle = MenuStyle.Fill;
        /// <summary>
        /// 菜单样式
        /// </summary>
        public MenuStyle MenuStyle
        {
            get { return m_menuStyle; }
            set { m_menuStyle = value; }
        }

        private List<Control> m_lstParentItems = new List<Control>();

        private IMenuItem m_selectParentItem = null;
        private IMenuItem m_selectChildrenItem = null;

        private Panel m_panChildren = null;

        private void ReloadItems()
        {
            try
            {
                ControlHelper.FreezeControl(this, true);
                this.Controls.Clear();
                m_lstParentItems.Clear();
                if (m_dataSource != null && m_dataSource.Count > 0)
                {
                    foreach (var parent in m_dataSource)
                    {
                        IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_parentItemType);
                        parentItem.DataSource = parent;
                        if (m_parentItemStyles != null)
                            parentItem.SetStyle(m_parentItemStyles);
                        parentItem.SelectedItem += parentItem_SelectedItem;
                        Control c = parentItem as Control;
                        c.Dock = DockStyle.Top;
                        this.Controls.Add(c);
                        this.Controls.SetChildIndex(c, 0);
                        m_lstParentItems.Add(c);
                    }
                }
                m_panChildren = new Panel();
                if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
                {
                    m_panChildren.Dock = DockStyle.Fill;
                    m_panChildren.Height = 0;
                }
                else
                {
                    m_panChildren.Dock = DockStyle.Top;
                    m_panChildren.Height = 0;
                }
                m_panChildren.AutoScroll = true;
                this.Controls.Add(m_panChildren);
            }
            finally
            {
                ControlHelper.FreezeControl(this, false);
            }

            if (m_isShowFirstItem && m_lstParentItems != null && m_lstParentItems.Count > 0)
            {
                parentItem_SelectedItem(m_lstParentItems[0], null);
            }
        }

        void parentItem_SelectedItem(object sender, EventArgs e)
        {
            this.FindForm().ActiveControl = this;
            IMenuItem item = sender as IMenuItem;
            if (m_lstParentItems.Contains(sender as Control))
            {
                if (m_selectParentItem != item)
                {
                    if (m_selectParentItem != null)
                    {
                        m_selectParentItem.SetSelectedStyle(false);
                    }
                    m_selectParentItem = item;
                    m_selectParentItem.SetSelectedStyle(true);
                    SetChildrenControl(m_selectParentItem);
                }
                else
                {
                    m_selectParentItem.SetSelectedStyle(false);
                    m_selectParentItem = null;
                    SetChildrenControl(m_selectParentItem, false);
                }
            }
            else if (m_panChildren.Controls.Contains(sender as Control))
            {
                if (m_selectChildrenItem != item)
                {
                    if (m_selectChildrenItem != null)
                    {
                        m_selectChildrenItem.SetSelectedStyle(false);
                    }
                    m_selectChildrenItem = item;
                    m_selectChildrenItem.SetSelectedStyle(true);
                }
            }
            if (SelectedItem != null)
            {
                SelectedItem(sender, e);
            }
        }

        private void SetChildrenControl(IMenuItem menuitem, bool blnChildren = true)
        {
            try
            {
                ControlHelper.FreezeControl(this, true);
                if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
                {
                    if (blnChildren)
                    {
                        Control cMenu = menuitem as Control;
                        int index = m_lstParentItems.IndexOf(cMenu);
                        for (int i = 0; i <= index; i++)
                        {
                            m_lstParentItems[i].Dock = DockStyle.Top;
                            this.Controls.SetChildIndex(m_lstParentItems[i], 1);
                        }
                        for (int i = index + 1; i < m_lstParentItems.Count; i++)
                        {
                            m_lstParentItems[i].Dock = DockStyle.Bottom;
                            this.Controls.SetChildIndex(m_lstParentItems[i], m_lstParentItems.Count);
                        }
                        m_panChildren.Controls.Clear();
                        int intItemHeigth = 0;
                        foreach (var item in menuitem.DataSource.Childrens)
                        {
                            IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
                            parentItem.DataSource = item;
                            if (m_childrenItemStyles != null)
                                parentItem.SetStyle(m_childrenItemStyles);
                            parentItem.SelectedItem += parentItem_SelectedItem;
                            Control c = parentItem as Control;
                            if (intItemHeigth == 0)
                                intItemHeigth = c.Height;
                            c.Dock = DockStyle.Top;
                            m_panChildren.Controls.Add(c);
                            m_panChildren.Controls.SetChildIndex(c, 0);
                        }
                        //m_panChildren.MinimumSize = new Size(0, menuitem.DataSource.Childrens.Count * intItemHeigth);
                    }
                    else
                    {
                        m_panChildren.Controls.Clear();
                        foreach (var item in m_lstParentItems)
                        {
                            item.Dock = DockStyle.Top;
                            this.Controls.SetChildIndex(item, 1);
                        }
                    }
                }
                else
                {
                    if (blnChildren)
                    {
                        Control cMenu = menuitem as Control;
                        int index = m_lstParentItems.IndexOf(cMenu);
                        this.Controls.SetChildIndex(m_panChildren, m_lstParentItems.Count - index - 1);
                        m_panChildren.Controls.Clear();
                        int intItemHeigth = 0;
                        foreach (var item in menuitem.DataSource.Childrens)
                        {
                            IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
                            parentItem.DataSource = item;
                            if (m_childrenItemStyles != null)
                                parentItem.SetStyle(m_childrenItemStyles);
                            parentItem.SelectedItem += parentItem_SelectedItem;
                            Control c = parentItem as Control;
                            if (intItemHeigth == 0)
                                intItemHeigth = c.Height;
                            c.Dock = DockStyle.Top;
                            m_panChildren.Controls.Add(c);
                            m_panChildren.Controls.SetChildIndex(c, 0);
                        }
                        m_panChildren.Height = menuitem.DataSource.Childrens.Count * intItemHeigth;
                    }
                    else
                    {
                        m_panChildren.Controls.Clear();
                        m_panChildren.Height = 0;
                    }
                }
            }
            finally
            {
                ControlHelper.FreezeControl(this, false);
            }
        }

        public UCMenu()
        {
            InitializeComponent();
        }
    }

    public enum MenuStyle
    {
        /// <summary>
        /// 平铺
        /// </summary>
        Fill = 1,
        /// <summary>
        /// 顶部对齐
        /// </summary>
        Top = 2,
    }

}
namespace HZH_Controls.Controls
{
    partial class UCMenu
    {
        /// <summary> 
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 组件设计器生成的代码

        /// <summary> 
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // UCMenu
            // 
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
            this.AutoScroll = true;
            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(30)))), ((int)(((byte)(39)))));
            this.Name = "UCMenu";
            this.Size = new System.Drawing.Size(204, 468);
            this.ResumeLayout(false);

        }

        #endregion

    }
}

用处及效果

示例代码

List<MenuItemEntity> lstMenu = new List<MenuItemEntity>();
            for (int i = 0; i < 5; i++)
            {
                MenuItemEntity item = new MenuItemEntity()
                {
                    Key = "p" + i.ToString(),
                    Text = "菜单项" + i,
                    DataSource = "这里编写一些自定义的数据源,用于扩展"
                };
                item.Childrens = new List<MenuItemEntity>();
                for (int j = 0; j < 5; j++)
                {
                    MenuItemEntity item2 = new MenuItemEntity()
                    {
                        Key = "c" + i.ToString(),
                        Text = "菜单子项" + i + "-" + j,
                        DataSource = "这里编写一些自定义的数据源,用于扩展"
                    };
                    item.Childrens.Add(item2);
                }
                lstMenu.Add(item);
            }
            this.ucMenu1.MenuStyle = MenuStyle.Top;  
            this.ucMenu1.DataSource = lstMenu;

最后的话

如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星 星吧

作者:冰封一夏
出处: http://www.hzhcontrols.com/doc.html
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,
且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git

原文出处:冰封一夏

原文链接:https://www.cnblogs.com/bfyx/p/11363432.html

本文观点不代表Dotnet9立场,转载请联系原作者。

发表评论

登录后才能评论