前提

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

本系列文章将讲解各种控件的开发及思路,欢迎各位批评指正。

此系列控件开发教程将全部在原生控件基础上进行重绘开发,目标的扁平化、漂亮、支持触屏。

如果有什么好的建议也可以评论留言来交流。

源码地址:

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

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

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

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

目录

http://toutiao.com/item/6824291838963220999/

准备工作

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

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

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

开始

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

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

再定义一个接口来约束

1  public interface IMenuItem 2     { 3         event EventHandler SelectedItem; 4         MenuItemEntity DataSource { get; set; } 5         ///  6         /// 设置样式 7         ///  8         /// key:属性名称,value:属性值 9         void SetStyle(Dictionary styles);10         /// 11         /// 设置选中样式12         /// 13         /// 是否选中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 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);            }        }

这样就完事了

设计效果就是这样子的了




treeselect怎么取选中的值的mc treeview获取选中节点_Source


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

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

这样就完成了

设计效果是这样子的


treeselect怎么取选中的值的mc treeview获取选中节点_子菜单挤压下方块元素_02


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

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

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

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

首先定义一个枚举

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

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

先看下有哪些属性

1  ///  2         /// 选中项事件 3         ///  4         public event EventHandler SelectedItem; 5         private Type m_parentItemType = typeof(UCMenuParentItem); 6         ///  7         /// 父类节点类型 8         ///  9         public Type ParentItemType10         {11             get { return m_parentItemType; }12             set13             {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         /// 25         /// 子类节点类型26         /// 27         public Type ChildrenItemType28         {29             get { return m_childrenItemType; }30             set31             {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 m_parentItemStyles;41         /// 42         /// 父类节点样式设置,key:属性名称,value:属性值43         /// 44         public Dictionary ParentItemStyles45         {46             get { return m_parentItemStyles; }47             set { m_parentItemStyles = value; }48         }49 50         private Dictionary m_childrenItemStyles;51         /// 52         /// 子类节点样式设置,key:属性名称,value:属性值53         /// 54         public Dictionary ChildrenItemStyles55         {56             get { return m_childrenItemStyles; }57             set { m_childrenItemStyles = value; }58         }59 60         private List m_dataSource;61         /// 62         /// 数据源63         /// 64         public List DataSource65         {66             get { return m_dataSource; }67             set68             {69                 m_dataSource = value;70 71                 ReloadItems();72             }73         }74         private bool m_isShowFirstItem = true;75         /// 76         /// 是否自动展开第一个节点77         /// 78         public bool IsShowFirstItem79         {80             get { return m_isShowFirstItem; }81             set { m_isShowFirstItem = value; }82         }83 84         private MenuStyle m_menuStyle = MenuStyle.Fill;85         /// 86         /// 菜单样式87         /// 88         public MenuStyle MenuStyle89         {90             get { return m_menuStyle; }91             set { m_menuStyle = value; }92         }93 94         private List m_lstParentItems = new List();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                 else31                 {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             finally39             {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                     else117                     {118                         m_panChildren.Controls.Clear();119                         m_panChildren.Height = 0;120                     }121                 }122             }123             finally124             {125                 ControlHelper.FreezeControl(this, false);126             }127         }

代码就这么多

用处及效果


treeselect怎么取选中的值的mc treeview获取选中节点_c# treeview查找并选中节点_03


示例代码

List lstMenu = new List();            for (int i = 0; i < 5; i++)            {                MenuItemEntity item = new MenuItemEntity()                {                    Key = "p" + i.ToString(),                    Text = "菜单项" + i,                    DataSource = "这里编写一些自定义的数据源,用于扩展"                };                item.Childrens = new List();                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;

最后的话

如果你喜欢的话,请到 码云或Github 点个星星吧