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

官网

http://www.hzhcontrols.com

前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

GitHub:https://github.com/kwwwvagaa/NetWinformControl

码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492 企鹅群568015492

目录

https://www.cnblogs.com/bfyx/p/11364884.html

准备工作

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

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

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

开始

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

 1     [Serializable]
 2     public class MenuItemEntity
 3     {
 4         /// <summary>
 5         /// 6         /// </summary>
 7         public string Key { get; set; }
 8         /// <summary>
 9         /// 文字
10         /// </summary>
11         public string Text { get; set; }
12         /// <summary>
13         /// 子节点
14         /// </summary>
15         public List<MenuItemEntity> Childrens { get; set; }
16         /// <summary>
17         /// 自定义数据源,一般用于扩展展示,比如定义节点图片等
18         /// </summary>
19         public object DataSource { get; set; }
20 
21     }

再定义一个接口来约束

 1  public interface IMenuItem
 2     {
 3         event EventHandler SelectedItem;
 4         MenuItemEntity DataSource { get; set; }
 5         /// <summary>
 6         /// 设置样式
 7         /// </summary>
 8         /// <param name="styles">key:属性名称,value:属性值</param>
 9         void SetStyle(Dictionary<string, object> styles);
10         /// <summary>
11         /// 设置选中样式
12         /// </summary>
13         /// <param name="blnSelected">是否选中</param>
14         void SetSelectedStyle(bool blnSelected);
15     }

首先看父节点定义,添加一个用户控件,命名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);
            }
        }

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

 1 // 版权所有  黄正辉  交流群:568015492   QQ:623128629
 2 // 文件名称:UCMenuParentItem.cs
 3 // 创建日期:2019-08-15 16:02:35
 4 // 功能描述:Menu
 5 // 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
 6 using System;
 7 using System.Collections.Generic;
 8 using System.ComponentModel;
 9 using System.Drawing;
10 using System.Data;
11 using System.Linq;
12 using System.Text;
13 using System.Windows.Forms;
14 
15 namespace HZH_Controls.Controls
16 {
17     /// <summary>
18     /// 父类节点
19     /// </summary>
20     [ToolboxItem(false)]
21     public partial class UCMenuParentItem : UserControl, IMenuItem
22     {
23         public event EventHandler SelectedItem;
24 
25         private MenuItemEntity m_dataSource;
26         public MenuItemEntity DataSource
27         {
28             get
29             {
30                 return m_dataSource;
31             }
32             set
33             {
34                 m_dataSource = value;
35                 if (value != null)
36                 {
37                     lblTitle.Text = value.Text;
38                 }
39             }
40         }
41 
42         public UCMenuParentItem()
43         {
44             InitializeComponent();
45             lblTitle.MouseDown += lblTitle_MouseDown;
46         }
47 
48         public void SetStyle(Dictionary<string, object> styles)
49         {
50             Type t = this.GetType();
51             foreach (var item in styles)
52             {
53                 var pro = t.GetProperty(item.Key);
54                 if (pro != null && pro.CanWrite)
55                 {
56                     try
57                     {
58                         pro.SetValue(this, item.Value, null);
59                     }
60                     catch (Exception ex)
61                     {
62                         throw new Exception("菜单元素设置样式异常", ex);
63                     }
64                 }
65             }
66         }
67 
68         public void SetSelectedStyle(bool blnSelected)
69         {
70             if (blnSelected)
71             {
72                 this.lblTitle.Image = Properties.Resources.sanjiao1;
73             }
74             else
75             {
76                 this.lblTitle.Image = Properties.Resources.sanjiao2;
77             }
78         }
79 
80         void lblTitle_MouseDown(object sender, MouseEventArgs e)
81         {
82             if (SelectedItem != null)
83             {
84                 SelectedItem(this, e);
85             }
86         }
87     }
88 }
View Code
 1 namespace HZH_Controls.Controls
 2 {
 3     partial class UCMenuParentItem
 4     {
 5         /// <summary> 
 6         /// 必需的设计器变量。
 7         /// </summary>
 8         private System.ComponentModel.IContainer components = null;
 9 
10         /// <summary> 
11         /// 清理所有正在使用的资源。
12         /// </summary>
13         /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
14         protected override void Dispose(bool disposing)
15         {
16             if (disposing && (components != null))
17             {
18                 components.Dispose();
19             }
20             base.Dispose(disposing);
21         }
22 
23         #region 组件设计器生成的代码
24 
25         /// <summary> 
26         /// 设计器支持所需的方法 - 不要
27         /// 使用代码编辑器修改此方法的内容。
28         /// </summary>
29         private void InitializeComponent()
30         {
31             this.ucSplitLine_H1 = new HZH_Controls.Controls.UCSplitLine_H();
32             this.lblTitle = new System.Windows.Forms.Label();
33             this.SuspendLayout();
34             // 
35             // ucSplitLine_H1
36             // 
37             this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(30)))), ((int)(((byte)(39)))));
38             this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom;
39             this.ucSplitLine_H1.Location = new System.Drawing.Point(0, 59);
40             this.ucSplitLine_H1.Name = "ucSplitLine_H1";
41             this.ucSplitLine_H1.Size = new System.Drawing.Size(200, 1);
42             this.ucSplitLine_H1.TabIndex = 0;
43             this.ucSplitLine_H1.TabStop = false;
44             // 
45             // lblTitle
46             // 
47             this.lblTitle.Dock = System.Windows.Forms.DockStyle.Fill;
48             this.lblTitle.ForeColor = System.Drawing.Color.White;
49             this.lblTitle.Image = global::HZH_Controls.Properties.Resources.sanjiao2;
50             this.lblTitle.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
51             this.lblTitle.Location = new System.Drawing.Point(0, 0);
52             this.lblTitle.Name = "lblTitle";
53             this.lblTitle.Size = new System.Drawing.Size(200, 59);
54             this.lblTitle.TabIndex = 1;
55             this.lblTitle.Text = "父项";
56             this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
57             // 
58             // UCMenuParentItem
59             // 
60             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
61             this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(43)))), ((int)(((byte)(54)))));
62             this.Controls.Add(this.lblTitle);
63             this.Controls.Add(this.ucSplitLine_H1);
64             this.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
65             this.Name = "UCMenuParentItem";
66             this.Size = new System.Drawing.Size(200, 60);
67             this.ResumeLayout(false);
68 
69         }
70 
71         #endregion
72 
73         private UCSplitLine_H ucSplitLine_H1;
74         private System.Windows.Forms.Label lblTitle;
75     }
76 }
View Code

设计效果就是这样子的了

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

添加用户控件,命名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);
                    }
                }
            }
        }

处理下点击事件

1  this.lblTitle.MouseDown += lblTitle_MouseDown;
2 
3        void lblTitle_MouseDown(object sender, MouseEventArgs e)
4         {
5             if (SelectedItem != null)
6             {
7                 SelectedItem(this, null);
8             }
9         }

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

 1 // 版权所有  黄正辉  交流群:568015492   QQ:623128629
 2 // 文件名称:UCMenuChildrenItem.cs
 3 // 创建日期:2019-08-15 16:02:26
 4 // 功能描述:Menu
 5 // 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
 6 using System;
 7 using System.Collections.Generic;
 8 using System.ComponentModel;
 9 using System.Drawing;
10 using System.Data;
11 using System.Linq;
12 using System.Text;
13 using System.Windows.Forms;
14 
15 namespace HZH_Controls.Controls
16 {
17     /// <summary>
18     /// 子类节点
19     /// </summary>
20     [ToolboxItem(false)]
21     public partial class UCMenuChildrenItem : UserControl, IMenuItem
22     {
23         public event EventHandler SelectedItem;
24 
25         private MenuItemEntity m_dataSource;
26         public MenuItemEntity DataSource
27         {
28             get
29             {
30                 return m_dataSource;
31             }
32             set
33             {
34                 m_dataSource = value;
35                 if (value != null)
36                 {
37                     lblTitle.Text = value.Text;
38                 }
39             }
40         }
41         public UCMenuChildrenItem()
42         {
43             InitializeComponent();
44             this.lblTitle.MouseDown += lblTitle_MouseDown;
45         }
46 
47         void lblTitle_MouseDown(object sender, MouseEventArgs e)
48         {
49             if (SelectedItem != null)
50             {
51                 SelectedItem(this, null);
52             }
53         }
54 
55         public void SetStyle(Dictionary<string, object> styles)
56         {
57             Type t = this.GetType();
58             foreach (var item in styles)
59             {
60                 var pro = t.GetProperty(item.Key);
61                 if (pro != null && pro.CanWrite)
62                 {
63                     try
64                     {
65                         pro.SetValue(this, item.Value, null);
66                     }
67                     catch (Exception ex)
68                     {
69                         throw new Exception("菜单元素设置样式异常", ex);
70                     }
71                 }
72             }
73         }
74 
75         public void SetSelectedStyle(bool blnSelected)
76         {
77 
78         }
79     }
80 }
View Code
 1 namespace HZH_Controls.Controls
 2 {
 3     partial class UCMenuChildrenItem
 4     {
 5         /// <summary> 
 6         /// 必需的设计器变量。
 7         /// </summary>
 8         private System.ComponentModel.IContainer components = null;
 9 
10         /// <summary> 
11         /// 清理所有正在使用的资源。
12         /// </summary>
13         /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
14         protected override void Dispose(bool disposing)
15         {
16             if (disposing && (components != null))
17             {
18                 components.Dispose();
19             }
20             base.Dispose(disposing);
21         }
22 
23         #region 组件设计器生成的代码
24 
25         /// <summary> 
26         /// 设计器支持所需的方法 - 不要
27         /// 使用代码编辑器修改此方法的内容。
28         /// </summary>
29         private void InitializeComponent()
30         {
31             this.ucSplitLine_H1 = new HZH_Controls.Controls.UCSplitLine_H();
32             this.lblTitle = new System.Windows.Forms.Label();
33             this.SuspendLayout();
34             // 
35             // ucSplitLine_H1
36             // 
37             this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(43)))), ((int)(((byte)(54)))));
38             this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom;
39             this.ucSplitLine_H1.Location = new System.Drawing.Point(0, 59);
40             this.ucSplitLine_H1.Name = "ucSplitLine_H1";
41             this.ucSplitLine_H1.Size = new System.Drawing.Size(200, 1);
42             this.ucSplitLine_H1.TabIndex = 0;
43             this.ucSplitLine_H1.TabStop = false;
44             // 
45             // lblTitle
46             // 
47             this.lblTitle.Dock = System.Windows.Forms.DockStyle.Fill;
48             this.lblTitle.Font = new System.Drawing.Font("微软雅黑", 12F);
49             this.lblTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(145)))), ((int)(((byte)(152)))), ((int)(((byte)(170)))));
50             this.lblTitle.Location = new System.Drawing.Point(0, 0);
51             this.lblTitle.Name = "lblTitle";
52             this.lblTitle.Size = new System.Drawing.Size(200, 59);
53             this.lblTitle.TabIndex = 1;
54             this.lblTitle.Text = "子项";
55             this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
56             // 
57             // UCMenuChildrenItem
58             // 
59             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
60             this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(30)))), ((int)(((byte)(39)))));
61             this.Controls.Add(this.lblTitle);
62             this.Controls.Add(this.ucSplitLine_H1);
63             this.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
64             this.Name = "UCMenuChildrenItem";
65             this.Size = new System.Drawing.Size(200, 60);
66             this.ResumeLayout(false);
67 
68         }
69 
70         #endregion
71 
72         private UCSplitLine_H ucSplitLine_H1;
73         private System.Windows.Forms.Label lblTitle;
74 
75     }
76 }
View Code

设计效果是这样子的

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

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

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

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

首先定义一个枚举

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

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

先看下有哪些属性

 1  /// <summary>
 2         /// 选中项事件
 3         /// </summary>
 4         public event EventHandler SelectedItem;
 5         private Type m_parentItemType = typeof(UCMenuParentItem);
 6         /// <summary>
 7         /// 父类节点类型
 8         /// </summary>
 9         public Type ParentItemType
10         {
11             get { return m_parentItemType; }
12             set
13             {
14                 if (value == null)
15                     return;
16                 if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
17                     throw new Exception("节点控件没有实现IMenuItem接口");
18                 m_parentItemType = value;
19 
20             }
21         }
22 
23         private Type m_childrenItemType = typeof(UCMenuChildrenItem);
24         /// <summary>
25         /// 子类节点类型
26         /// </summary>
27         public Type ChildrenItemType
28         {
29             get { return m_childrenItemType; }
30             set
31             {
32                 if (value == null)
33                     return;
34                 if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
35                     throw new Exception("节点控件没有实现IMenuItem接口");
36                 m_childrenItemType = value;
37             }
38         }
39 
40         private Dictionary<string, object> m_parentItemStyles;
41         /// <summary>
42         /// 父类节点样式设置,key:属性名称,value:属性值
43         /// </summary>
44         public Dictionary<string, object> ParentItemStyles
45         {
46             get { return m_parentItemStyles; }
47             set { m_parentItemStyles = value; }
48         }
49 
50         private Dictionary<string, object> m_childrenItemStyles;
51         /// <summary>
52         /// 子类节点样式设置,key:属性名称,value:属性值
53         /// </summary>
54         public Dictionary<string, object> ChildrenItemStyles
55         {
56             get { return m_childrenItemStyles; }
57             set { m_childrenItemStyles = value; }
58         }
59 
60         private List<MenuItemEntity> m_dataSource;
61         /// <summary>
62         /// 数据源
63         /// </summary>
64         public List<MenuItemEntity> DataSource
65         {
66             get { return m_dataSource; }
67             set
68             {
69                 m_dataSource = value;
70 
71                 ReloadItems();
72             }
73         }
74         private bool m_isShowFirstItem = true;
75         /// <summary>
76         /// 是否自动展开第一个节点
77         /// </summary>
78         public bool IsShowFirstItem
79         {
80             get { return m_isShowFirstItem; }
81             set { m_isShowFirstItem = value; }
82         }
83 
84         private MenuStyle m_menuStyle = MenuStyle.Fill;
85         /// <summary>
86         /// 菜单样式
87         /// </summary>
88         public MenuStyle MenuStyle
89         {
90             get { return m_menuStyle; }
91             set { m_menuStyle = value; }
92         }
93 
94         private List<Control> m_lstParentItems = new List<Control>();
95 
96         private IMenuItem m_selectParentItem = null;
97         private IMenuItem m_selectChildrenItem = null;
98 
99         private Panel m_panChildren = null;

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

 1 private void ReloadItems()
 2         {
 3             try
 4             {
 5                 ControlHelper.FreezeControl(this, true);
 6                 this.Controls.Clear();
 7                 m_lstParentItems.Clear();
 8                 if (m_dataSource != null && m_dataSource.Count > 0)
 9                 {
10                     foreach (var parent in m_dataSource)
11                     {
12                         IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_parentItemType);
13                         parentItem.DataSource = parent;
14                         if (m_parentItemStyles != null)
15                             parentItem.SetStyle(m_parentItemStyles);
16                         parentItem.SelectedItem += parentItem_SelectedItem;
17                         Control c = parentItem as Control;
18                         c.Dock = DockStyle.Top;
19                         this.Controls.Add(c);
20                         this.Controls.SetChildIndex(c, 0);
21                         m_lstParentItems.Add(c);
22                     }
23                 }
24                 m_panChildren = new Panel();
25                 if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
26                 {
27                     m_panChildren.Dock = DockStyle.Fill;
28                     m_panChildren.Height = 0;
29                 }
30                 else
31                 {
32                     m_panChildren.Dock = DockStyle.Top;
33                     m_panChildren.Height = 0;
34                 }
35                 m_panChildren.AutoScroll = true;
36                 this.Controls.Add(m_panChildren);
37             }
38             finally
39             {
40                 ControlHelper.FreezeControl(this, false);
41             }
42 
43             if (m_isShowFirstItem && m_lstParentItems != null && m_lstParentItems.Count > 0)
44             {
45                 parentItem_SelectedItem(m_lstParentItems[0], null);
46             }
47         }

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

  1  void parentItem_SelectedItem(object sender, EventArgs e)
  2         {
  3             this.FindForm().ActiveControl = this;
  4             IMenuItem item = sender as IMenuItem;
  5             if (m_lstParentItems.Contains(sender as Control))
  6             {
  7                 if (m_selectParentItem != item)
  8                 {
  9                     if (m_selectParentItem != null)
 10                     {
 11                         m_selectParentItem.SetSelectedStyle(false);
 12                     }
 13                     m_selectParentItem = item;
 14                     m_selectParentItem.SetSelectedStyle(true);
 15                     SetChildrenControl(m_selectParentItem);
 16                 }
 17                 else
 18                 {
 19                     m_selectParentItem.SetSelectedStyle(false);
 20                     m_selectParentItem = null;
 21                     SetChildrenControl(m_selectParentItem, false);
 22                 }
 23             }
 24             else if (m_panChildren.Controls.Contains(sender as Control))
 25             {
 26                 if (m_selectChildrenItem != item)
 27                 {
 28                     if (m_selectChildrenItem != null)
 29                     {
 30                         m_selectChildrenItem.SetSelectedStyle(false);
 31                     }
 32                     m_selectChildrenItem = item;
 33                     m_selectChildrenItem.SetSelectedStyle(true);
 34                 }
 35             }
 36             if (SelectedItem != null)
 37             {
 38                 SelectedItem(sender, e);
 39             }
 40         }
 41 
 42         private void SetChildrenControl(IMenuItem menuitem, bool blnChildren = true)
 43         {
 44             try
 45             {
 46                 ControlHelper.FreezeControl(this, true);
 47                 if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
 48                 {
 49                     if (blnChildren)
 50                     {
 51                         Control cMenu = menuitem as Control;
 52                         int index = m_lstParentItems.IndexOf(cMenu);
 53                         for (int i = 0; i <= index; i++)
 54                         {
 55                             m_lstParentItems[i].Dock = DockStyle.Top;
 56                             this.Controls.SetChildIndex(m_lstParentItems[i], 1);
 57                         }
 58                         for (int i = index + 1; i < m_lstParentItems.Count; i++)
 59                         {
 60                             m_lstParentItems[i].Dock = DockStyle.Bottom;
 61                             this.Controls.SetChildIndex(m_lstParentItems[i], m_lstParentItems.Count);
 62                         }
 63                         m_panChildren.Controls.Clear();
 64                         int intItemHeigth = 0;
 65                         foreach (var item in menuitem.DataSource.Childrens)
 66                         {
 67                             IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
 68                             parentItem.DataSource = item;
 69                             if (m_childrenItemStyles != null)
 70                                 parentItem.SetStyle(m_childrenItemStyles);
 71                             parentItem.SelectedItem += parentItem_SelectedItem;
 72                             Control c = parentItem as Control;
 73                             if (intItemHeigth == 0)
 74                                 intItemHeigth = c.Height;
 75                             c.Dock = DockStyle.Top;
 76                             m_panChildren.Controls.Add(c);
 77                             m_panChildren.Controls.SetChildIndex(c, 0);
 78                         }
 79                         //m_panChildren.MinimumSize = new Size(0, menuitem.DataSource.Childrens.Count * intItemHeigth);
 80                     }
 81                     else
 82                     {
 83                         m_panChildren.Controls.Clear();
 84                         foreach (var item in m_lstParentItems)
 85                         {
 86                             item.Dock = DockStyle.Top;
 87                             this.Controls.SetChildIndex(item, 1);
 88                         }
 89                     }
 90                 }
 91                 else
 92                 {
 93                     if (blnChildren)
 94                     {
 95                         Control cMenu = menuitem as Control;
 96                         int index = m_lstParentItems.IndexOf(cMenu);
 97                         this.Controls.SetChildIndex(m_panChildren, m_lstParentItems.Count - index - 1);
 98                         m_panChildren.Controls.Clear();
 99                         int intItemHeigth = 0;
100                         foreach (var item in menuitem.DataSource.Childrens)
101                         {
102                             IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
103                             parentItem.DataSource = item;
104                             if (m_childrenItemStyles != null)
105                                 parentItem.SetStyle(m_childrenItemStyles);
106                             parentItem.SelectedItem += parentItem_SelectedItem;
107                             Control c = parentItem as Control;
108                             if (intItemHeigth == 0)
109                                 intItemHeigth = c.Height;
110                             c.Dock = DockStyle.Top;
111                             m_panChildren.Controls.Add(c);
112                             m_panChildren.Controls.SetChildIndex(c, 0);
113                         }
114                         m_panChildren.Height = menuitem.DataSource.Childrens.Count * intItemHeigth;
115                     }
116                     else
117                     {
118                         m_panChildren.Controls.Clear();
119                         m_panChildren.Height = 0;
120                     }
121                 }
122             }
123             finally
124             {
125                 ControlHelper.FreezeControl(this, false);
126             }
127         }

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

  1 // 版权所有  黄正辉  交流群:568015492   QQ:623128629
  2 // 文件名称:UCMenu.cs
  3 // 创建日期:2019-08-15 16:02:22
  4 // 功能描述:Menu
  5 // 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
  6 using System;
  7 using System.Collections.Generic;
  8 using System.ComponentModel;
  9 using System.Drawing;
 10 using System.Data;
 11 using System.Linq;
 12 using System.Text;
 13 using System.Windows.Forms;
 14 
 15 namespace HZH_Controls.Controls
 16 {
 17     public partial class UCMenu : UserControl
 18     {
 19         /// <summary>
 20         /// 选中项事件
 21         /// </summary>
 22         public event EventHandler SelectedItem;
 23         private Type m_parentItemType = typeof(UCMenuParentItem);
 24         /// <summary>
 25         /// 父类节点类型
 26         /// </summary>
 27         public Type ParentItemType
 28         {
 29             get { return m_parentItemType; }
 30             set
 31             {
 32                 if (value == null)
 33                     return;
 34                 if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
 35                     throw new Exception("节点控件没有实现IMenuItem接口");
 36                 m_parentItemType = value;
 37 
 38             }
 39         }
 40 
 41         private Type m_childrenItemType = typeof(UCMenuChildrenItem);
 42         /// <summary>
 43         /// 子类节点类型
 44         /// </summary>
 45         public Type ChildrenItemType
 46         {
 47             get { return m_childrenItemType; }
 48             set
 49             {
 50                 if (value == null)
 51                     return;
 52                 if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
 53                     throw new Exception("节点控件没有实现IMenuItem接口");
 54                 m_childrenItemType = value;
 55             }
 56         }
 57 
 58         private Dictionary<string, object> m_parentItemStyles;
 59         /// <summary>
 60         /// 父类节点样式设置,key:属性名称,value:属性值
 61         /// </summary>
 62         public Dictionary<string, object> ParentItemStyles
 63         {
 64             get { return m_parentItemStyles; }
 65             set { m_parentItemStyles = value; }
 66         }
 67 
 68         private Dictionary<string, object> m_childrenItemStyles;
 69         /// <summary>
 70         /// 子类节点样式设置,key:属性名称,value:属性值
 71         /// </summary>
 72         public Dictionary<string, object> ChildrenItemStyles
 73         {
 74             get { return m_childrenItemStyles; }
 75             set { m_childrenItemStyles = value; }
 76         }
 77 
 78         private List<MenuItemEntity> m_dataSource;
 79         /// <summary>
 80         /// 数据源
 81         /// </summary>
 82         public List<MenuItemEntity> DataSource
 83         {
 84             get { return m_dataSource; }
 85             set
 86             {
 87                 m_dataSource = value;
 88 
 89                 ReloadItems();
 90             }
 91         }
 92         private bool m_isShowFirstItem = true;
 93         /// <summary>
 94         /// 是否自动展开第一个节点
 95         /// </summary>
 96         public bool IsShowFirstItem
 97         {
 98             get { return m_isShowFirstItem; }
 99             set { m_isShowFirstItem = value; }
100         }
101 
102         private MenuStyle m_menuStyle = MenuStyle.Fill;
103         /// <summary>
104         /// 菜单样式
105         /// </summary>
106         public MenuStyle MenuStyle
107         {
108             get { return m_menuStyle; }
109             set { m_menuStyle = value; }
110         }
111 
112         private List<Control> m_lstParentItems = new List<Control>();
113 
114         private IMenuItem m_selectParentItem = null;
115         private IMenuItem m_selectChildrenItem = null;
116 
117         private Panel m_panChildren = null;
118 
119         private void ReloadItems()
120         {
121             try
122             {
123                 ControlHelper.FreezeControl(this, true);
124                 this.Controls.Clear();
125                 m_lstParentItems.Clear();
126                 if (m_dataSource != null && m_dataSource.Count > 0)
127                 {
128                     foreach (var parent in m_dataSource)
129                     {
130                         IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_parentItemType);
131                         parentItem.DataSource = parent;
132                         if (m_parentItemStyles != null)
133                             parentItem.SetStyle(m_parentItemStyles);
134                         parentItem.SelectedItem += parentItem_SelectedItem;
135                         Control c = parentItem as Control;
136                         c.Dock = DockStyle.Top;
137                         this.Controls.Add(c);
138                         this.Controls.SetChildIndex(c, 0);
139                         m_lstParentItems.Add(c);
140                     }
141                 }
142                 m_panChildren = new Panel();
143                 if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
144                 {
145                     m_panChildren.Dock = DockStyle.Fill;
146                     m_panChildren.Height = 0;
147                 }
148                 else
149                 {
150                     m_panChildren.Dock = DockStyle.Top;
151                     m_panChildren.Height = 0;
152                 }
153                 m_panChildren.AutoScroll = true;
154                 this.Controls.Add(m_panChildren);
155             }
156             finally
157             {
158                 ControlHelper.FreezeControl(this, false);
159             }
160 
161             if (m_isShowFirstItem && m_lstParentItems != null && m_lstParentItems.Count > 0)
162             {
163                 parentItem_SelectedItem(m_lstParentItems[0], null);
164             }
165         }
166 
167         void parentItem_SelectedItem(object sender, EventArgs e)
168         {
169             this.FindForm().ActiveControl = this;
170             IMenuItem item = sender as IMenuItem;
171             if (m_lstParentItems.Contains(sender as Control))
172             {
173                 if (m_selectParentItem != item)
174                 {
175                     if (m_selectParentItem != null)
176                     {
177                         m_selectParentItem.SetSelectedStyle(false);
178                     }
179                     m_selectParentItem = item;
180                     m_selectParentItem.SetSelectedStyle(true);
181                     SetChildrenControl(m_selectParentItem);
182                 }
183                 else
184                 {
185                     m_selectParentItem.SetSelectedStyle(false);
186                     m_selectParentItem = null;
187                     SetChildrenControl(m_selectParentItem, false);
188                 }
189             }
190             else if (m_panChildren.Controls.Contains(sender as Control))
191             {
192                 if (m_selectChildrenItem != item)
193                 {
194                     if (m_selectChildrenItem != null)
195                     {
196                         m_selectChildrenItem.SetSelectedStyle(false);
197                     }
198                     m_selectChildrenItem = item;
199                     m_selectChildrenItem.SetSelectedStyle(true);
200                 }
201             }
202             if (SelectedItem != null)
203             {
204                 SelectedItem(sender, e);
205             }
206         }
207 
208         private void SetChildrenControl(IMenuItem menuitem, bool blnChildren = true)
209         {
210             try
211             {
212                 ControlHelper.FreezeControl(this, true);
213                 if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
214                 {
215                     if (blnChildren)
216                     {
217                         Control cMenu = menuitem as Control;
218                         int index = m_lstParentItems.IndexOf(cMenu);
219                         for (int i = 0; i <= index; i++)
220                         {
221                             m_lstParentItems[i].Dock = DockStyle.Top;
222                             this.Controls.SetChildIndex(m_lstParentItems[i], 1);
223                         }
224                         for (int i = index + 1; i < m_lstParentItems.Count; i++)
225                         {
226                             m_lstParentItems[i].Dock = DockStyle.Bottom;
227                             this.Controls.SetChildIndex(m_lstParentItems[i], m_lstParentItems.Count);
228                         }
229                         m_panChildren.Controls.Clear();
230                         int intItemHeigth = 0;
231                         foreach (var item in menuitem.DataSource.Childrens)
232                         {
233                             IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
234                             parentItem.DataSource = item;
235                             if (m_childrenItemStyles != null)
236                                 parentItem.SetStyle(m_childrenItemStyles);
237                             parentItem.SelectedItem += parentItem_SelectedItem;
238                             Control c = parentItem as Control;
239                             if (intItemHeigth == 0)
240                                 intItemHeigth = c.Height;
241                             c.Dock = DockStyle.Top;
242                             m_panChildren.Controls.Add(c);
243                             m_panChildren.Controls.SetChildIndex(c, 0);
244                         }
245                         //m_panChildren.MinimumSize = new Size(0, menuitem.DataSource.Childrens.Count * intItemHeigth);
246                     }
247                     else
248                     {
249                         m_panChildren.Controls.Clear();
250                         foreach (var item in m_lstParentItems)
251                         {
252                             item.Dock = DockStyle.Top;
253                             this.Controls.SetChildIndex(item, 1);
254                         }
255                     }
256                 }
257                 else
258                 {
259                     if (blnChildren)
260                     {
261                         Control cMenu = menuitem as Control;
262                         int index = m_lstParentItems.IndexOf(cMenu);
263                         this.Controls.SetChildIndex(m_panChildren, m_lstParentItems.Count - index - 1);
264                         m_panChildren.Controls.Clear();
265                         int intItemHeigth = 0;
266                         foreach (var item in menuitem.DataSource.Childrens)
267                         {
268                             IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
269                             parentItem.DataSource = item;
270                             if (m_childrenItemStyles != null)
271                                 parentItem.SetStyle(m_childrenItemStyles);
272                             parentItem.SelectedItem += parentItem_SelectedItem;
273                             Control c = parentItem as Control;
274                             if (intItemHeigth == 0)
275                                 intItemHeigth = c.Height;
276                             c.Dock = DockStyle.Top;
277                             m_panChildren.Controls.Add(c);
278                             m_panChildren.Controls.SetChildIndex(c, 0);
279                         }
280                         m_panChildren.Height = menuitem.DataSource.Childrens.Count * intItemHeigth;
281                     }
282                     else
283                     {
284                         m_panChildren.Controls.Clear();
285                         m_panChildren.Height = 0;
286                     }
287                 }
288             }
289             finally
290             {
291                 ControlHelper.FreezeControl(this, false);
292             }
293         }
294 
295         public UCMenu()
296         {
297             InitializeComponent();
298         }
299     }
300 
301     public enum MenuStyle
302     {
303         /// <summary>
304         /// 平铺
305         /// </summary>
306         Fill = 1,
307         /// <summary>
308         /// 顶部对齐
309         /// </summary>
310         Top = 2,
311     }
312 
313 }
View Code
 1 namespace HZH_Controls.Controls
 2 {
 3     partial class UCMenu
 4     {
 5         /// <summary> 
 6         /// 必需的设计器变量。
 7         /// </summary>
 8         private System.ComponentModel.IContainer components = null;
 9 
10         /// <summary> 
11         /// 清理所有正在使用的资源。
12         /// </summary>
13         /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
14         protected override void Dispose(bool disposing)
15         {
16             if (disposing && (components != null))
17             {
18                 components.Dispose();
19             }
20             base.Dispose(disposing);
21         }
22 
23         #region 组件设计器生成的代码
24 
25         /// <summary> 
26         /// 设计器支持所需的方法 - 不要
27         /// 使用代码编辑器修改此方法的内容。
28         /// </summary>
29         private void InitializeComponent()
30         {
31             this.SuspendLayout();
32             // 
33             // UCMenu
34             // 
35             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
36             this.AutoScroll = true;
37             this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(30)))), ((int)(((byte)(39)))));
38             this.Name = "UCMenu";
39             this.Size = new System.Drawing.Size(204, 468);
40             this.ResumeLayout(false);
41 
42         }
43 
44         #endregion
45 
46     }
47 }
View Code

用处及效果

示例代码

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 点个星 星吧

原文地址:https://www.cnblogs.com/bfyx/p/11363432.html