前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果觉得写的还行,请点个 star 支持一下吧
目录
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 }
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