官网
前提
入行已经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步操作,1:创建项控件,2:创建列表控件
开始
首先我们创建项控件,添加一个用户控件,命名UCHorizontalListItem
代码量并不多,我们看下完整代码
1 // 版权所有 黄正辉 交流群:568015492 QQ:623128629 2 // 文件名称:UCHorizontalListItem.cs 3 // 创建日期:2019-08-15 16:01:13 4 // 功能描述:HorizontalList 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 [ToolboxItem(false)] 18 public partial class UCHorizontalListItem : UserControl 19 { 20 public event EventHandler SelectedItem; 21 private KeyValuePair<string, string> _DataSource = new KeyValuePair<string, string>(); 22 public KeyValuePair<string, string> DataSource 23 { 24 get { return _DataSource; } 25 set 26 { 27 _DataSource = value; 28 int intWidth = ControlHelper.GetStringWidth(value.Value, lblTitle.CreateGraphics(), lblTitle.Font); 29 if (intWidth < 50) 30 intWidth = 50; 31 this.Width = intWidth + 20; 32 lblTitle.Text = value.Value; 33 SetSelect(false); 34 } 35 } 36 public UCHorizontalListItem() 37 { 38 InitializeComponent(); 39 this.Dock = DockStyle.Right; 40 this.MouseDown += Item_MouseDown; 41 this.lblTitle.MouseDown += Item_MouseDown; 42 this.ucSplitLine_H1.MouseDown += Item_MouseDown; 43 } 44 45 void Item_MouseDown(object sender, MouseEventArgs e) 46 { 47 if (SelectedItem != null) 48 SelectedItem(this, e); 49 } 50 51 public void SetSelect(bool bln) 52 { 53 if (bln) 54 { 55 lblTitle.ForeColor = Color.FromArgb(255, 77, 59); 56 ucSplitLine_H1.Visible = true; 57 this.lblTitle.Padding = new Padding(0, 0, 0, 5); 58 } 59 else 60 { 61 lblTitle.ForeColor = Color.FromArgb(64, 64, 64); 62 ucSplitLine_H1.Visible = false; 63 this.lblTitle.Padding = new Padding(0, 0, 0, 0); 64 } 65 } 66 } 67 }
1 namespace HZH_Controls.Controls 2 { 3 partial class UCHorizontalListItem 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.lblTitle = new System.Windows.Forms.Label(); 32 this.ucSplitLine_H1 = new HZH_Controls.Controls.UCSplitLine_H(); 33 this.SuspendLayout(); 34 // 35 // lblTitle 36 // 37 this.lblTitle.Dock = System.Windows.Forms.DockStyle.Fill; 38 this.lblTitle.Font = new System.Drawing.Font("微软雅黑", 10F); 39 this.lblTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); 40 this.lblTitle.Location = new System.Drawing.Point(1, 0); 41 this.lblTitle.Name = "lblTitle"; 42 this.lblTitle.Padding = new System.Windows.Forms.Padding(0, 0, 0, 10); 43 this.lblTitle.Size = new System.Drawing.Size(118, 50); 44 this.lblTitle.TabIndex = 1; 45 this.lblTitle.Text = "分类名称 分类名称"; 46 this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 47 // 48 // ucSplitLine_H1 49 // 50 this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(77)))), ((int)(((byte)(59))))); 51 this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom; 52 this.ucSplitLine_H1.Location = new System.Drawing.Point(1, 50); 53 this.ucSplitLine_H1.Name = "ucSplitLine_H1"; 54 this.ucSplitLine_H1.Size = new System.Drawing.Size(118, 3); 55 this.ucSplitLine_H1.TabIndex = 0; 56 this.ucSplitLine_H1.TabStop = false; 57 // 58 // UCHorizontalListItem 59 // 60 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 61 this.Controls.Add(this.lblTitle); 62 this.Controls.Add(this.ucSplitLine_H1); 63 this.Name = "UCHorizontalListItem"; 64 this.Padding = new System.Windows.Forms.Padding(1, 0, 1, 0); 65 this.Size = new System.Drawing.Size(120, 53); 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 }
设计效果如图
接着我们来创建列表控件,添加一个用户控件,命名UCHorizontalList
我们看下需要提供哪些属性
public UCHorizontalListItem SelectedItem { get; set; } public event EventHandler SelectedItemEvent; private int m_startItemIndex = 0; private bool isAutoSelectFirst = true; public bool IsAutoSelectFirst { get { return isAutoSelectFirst; } set { isAutoSelectFirst = value; } } private List<KeyValuePair<string, string>> dataSource = null; public List<KeyValuePair<string, string>> DataSource { get { return dataSource; } set { dataSource = value; ReloadSource(); } }
我们有时需要刷新列表
1 public void ReloadSource() 2 { 3 try 4 { 5 ControlHelper.FreezeControl(this, true); 6 this.panList.SuspendLayout(); 7 this.panList.Controls.Clear(); 8 this.panList.Width = this.panMain.Width; 9 if (DataSource != null) 10 { 11 foreach (var item in DataSource) 12 { 13 UCHorizontalListItem uc = new UCHorizontalListItem(); 14 uc.DataSource = item; 15 uc.SelectedItem += uc_SelectItem; 16 this.panList.Controls.Add(uc); 17 } 18 } 19 this.panList.ResumeLayout(true); 20 if (this.panList.Controls.Count > 0) 21 this.panList.Width = panMain.Width + this.panList.Controls[0].Location.X * -1; 22 this.panList.Location = new Point(0, 0); 23 m_startItemIndex = 0; 24 if (this.panList.Width > panMain.Width) 25 panRight.Visible = true; 26 else 27 panRight.Visible = false; 28 panLeft.Visible = false; 29 panList.SendToBack(); 30 panRight.SendToBack(); 31 if (isAutoSelectFirst && DataSource != null && DataSource.Count > 0) 32 { 33 SelectItem((UCHorizontalListItem)this.panList.Controls[0]); 34 } 35 } 36 finally 37 { 38 ControlHelper.FreezeControl(this, false); 39 } 40 }
还需要处理选中处理
1 private void SelectItem(UCHorizontalListItem item) 2 { 3 if (SelectedItem != null && !SelectedItem.IsDisposed) 4 SelectedItem.SetSelect(false); 5 SelectedItem = item; 6 SelectedItem.SetSelect(true); 7 if (SelectedItemEvent != null) 8 SelectedItemEvent(item, null); 9 }
然后就是翻页功能的处理了
1 private void panLeft_MouseDown(object sender, MouseEventArgs e) 2 { 3 if (this.panList.Location.X >= 0) 4 { 5 this.panList.Location = new Point(0, 0); 6 return; 7 } 8 9 for (int i = m_startItemIndex; i >= 0; i--) 10 { 11 if (this.panList.Controls[i].Location.X < this.panList.Controls[m_startItemIndex].Location.X - panMain.Width) 12 { 13 m_startItemIndex = i + 1; 14 break; ; 15 } 16 if (i == 0) 17 { 18 m_startItemIndex = 0; 19 } 20 } 21 22 ResetListLocation(); 23 panRight.Visible = true; 24 if (this.panList.Location.X >= 0) 25 { 26 panLeft.Visible = false; 27 } 28 else 29 { 30 panLeft.Visible = true; 31 } 32 panList.SendToBack(); 33 panRight.SendToBack(); 34 } 35 36 private void panRight_MouseDown(object sender, MouseEventArgs e) 37 { 38 if (this.panList.Location.X + this.panList.Width <= this.panMain.Width) 39 return; 40 if (this.panList.Controls.Count <= 0) 41 return; 42 for (int i = m_startItemIndex; i < this.panList.Controls.Count; i++) 43 { 44 if (this.panList.Location.X + this.panList.Controls[i].Location.X + this.panList.Controls[i].Width > panMain.Width) 45 { 46 m_startItemIndex = i; 47 break; 48 } 49 } 50 ResetListLocation(); 51 panLeft.Visible = true; 52 if (panList.Width + panList.Location.X <= panMain.Width) 53 panRight.Visible = false; 54 else 55 panRight.Visible = true; 56 panList.SendToBack(); 57 panRight.SendToBack(); 58 } 59 60 private void ResetListLocation() 61 { 62 if (this.panList.Controls.Count > 0) 63 { 64 this.panList.Location = new Point(this.panList.Controls[m_startItemIndex].Location.X * -1, 0); 65 } 66 }
最后向外暴露一个设置选中的功能
1 public void SetSelect(string strKey) 2 { 3 foreach (UCHorizontalListItem item in this.panList.Controls) 4 { 5 if (item.DataSource.Key == strKey) 6 { 7 SelectItem(item); 8 return; 9 } 10 } 11 }
以上就是主要东西了,再看下完整代码
1 // 版权所有 黄正辉 交流群:568015492 QQ:623128629 2 // 文件名称:UCHorizontalList.cs 3 // 创建日期:2019-08-15 16:01:06 4 // 功能描述:HorizontalList 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 UCHorizontalList : UserControl 18 { 19 public UCHorizontalListItem SelectedItem { get; set; } 20 public event EventHandler SelectedItemEvent; 21 private int m_startItemIndex = 0; 22 private bool isAutoSelectFirst = true; 23 24 public bool IsAutoSelectFirst 25 { 26 get { return isAutoSelectFirst; } 27 set { isAutoSelectFirst = value; } 28 } 29 30 private List<KeyValuePair<string, string>> dataSource = null; 31 32 public List<KeyValuePair<string, string>> DataSource 33 { 34 get { return dataSource; } 35 set 36 { 37 dataSource = value; 38 ReloadSource(); 39 } 40 } 41 42 public UCHorizontalList() 43 { 44 InitializeComponent(); 45 } 46 47 public void ReloadSource() 48 { 49 try 50 { 51 ControlHelper.FreezeControl(this, true); 52 this.panList.SuspendLayout(); 53 this.panList.Controls.Clear(); 54 this.panList.Width = this.panMain.Width; 55 if (DataSource != null) 56 { 57 foreach (var item in DataSource) 58 { 59 UCHorizontalListItem uc = new UCHorizontalListItem(); 60 uc.DataSource = item; 61 uc.SelectedItem += uc_SelectItem; 62 this.panList.Controls.Add(uc); 63 } 64 } 65 this.panList.ResumeLayout(true); 66 if (this.panList.Controls.Count > 0) 67 this.panList.Width = panMain.Width + this.panList.Controls[0].Location.X * -1; 68 this.panList.Location = new Point(0, 0); 69 m_startItemIndex = 0; 70 if (this.panList.Width > panMain.Width) 71 panRight.Visible = true; 72 else 73 panRight.Visible = false; 74 panLeft.Visible = false; 75 panList.SendToBack(); 76 panRight.SendToBack(); 77 if (isAutoSelectFirst && DataSource != null && DataSource.Count > 0) 78 { 79 SelectItem((UCHorizontalListItem)this.panList.Controls[0]); 80 } 81 } 82 finally 83 { 84 ControlHelper.FreezeControl(this, false); 85 } 86 } 87 88 void uc_SelectItem(object sender, EventArgs e) 89 { 90 SelectItem(sender as UCHorizontalListItem); 91 } 92 93 private void SelectItem(UCHorizontalListItem item) 94 { 95 if (SelectedItem != null && !SelectedItem.IsDisposed) 96 SelectedItem.SetSelect(false); 97 SelectedItem = item; 98 SelectedItem.SetSelect(true); 99 if (SelectedItemEvent != null) 100 SelectedItemEvent(item, null); 101 } 102 103 private void panLeft_MouseDown(object sender, MouseEventArgs e) 104 { 105 if (this.panList.Location.X >= 0) 106 { 107 this.panList.Location = new Point(0, 0); 108 return; 109 } 110 111 for (int i = m_startItemIndex; i >= 0; i--) 112 { 113 if (this.panList.Controls[i].Location.X < this.panList.Controls[m_startItemIndex].Location.X - panMain.Width) 114 { 115 m_startItemIndex = i + 1; 116 break; ; 117 } 118 if (i == 0) 119 { 120 m_startItemIndex = 0; 121 } 122 } 123 124 ResetListLocation(); 125 panRight.Visible = true; 126 if (this.panList.Location.X >= 0) 127 { 128 panLeft.Visible = false; 129 } 130 else 131 { 132 panLeft.Visible = true; 133 } 134 panList.SendToBack(); 135 panRight.SendToBack(); 136 } 137 138 private void panRight_MouseDown(object sender, MouseEventArgs e) 139 { 140 if (this.panList.Location.X + this.panList.Width <= this.panMain.Width) 141 return; 142 if (this.panList.Controls.Count <= 0) 143 return; 144 for (int i = m_startItemIndex; i < this.panList.Controls.Count; i++) 145 { 146 if (this.panList.Location.X + this.panList.Controls[i].Location.X + this.panList.Controls[i].Width > panMain.Width) 147 { 148 m_startItemIndex = i; 149 break; 150 } 151 } 152 ResetListLocation(); 153 panLeft.Visible = true; 154 if (panList.Width + panList.Location.X <= panMain.Width) 155 panRight.Visible = false; 156 else 157 panRight.Visible = true; 158 panList.SendToBack(); 159 panRight.SendToBack(); 160 } 161 162 private void ResetListLocation() 163 { 164 if (this.panList.Controls.Count > 0) 165 { 166 this.panList.Location = new Point(this.panList.Controls[m_startItemIndex].Location.X * -1, 0); 167 } 168 } 169 170 public void SetSelect(string strKey) 171 { 172 foreach (UCHorizontalListItem item in this.panList.Controls) 173 { 174 if (item.DataSource.Key == strKey) 175 { 176 SelectItem(item); 177 return; 178 } 179 } 180 } 181 } 182 }
1 namespace HZH_Controls.Controls 2 { 3 partial class UCHorizontalList 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.panMain = new System.Windows.Forms.Panel(); 32 this.panList = new System.Windows.Forms.Panel(); 33 this.panRight = new System.Windows.Forms.Panel(); 34 this.panLeft = new System.Windows.Forms.Panel(); 35 this.panMain.SuspendLayout(); 36 this.SuspendLayout(); 37 // 38 // panMain 39 // 40 this.panMain.Controls.Add(this.panList); 41 this.panMain.Dock = System.Windows.Forms.DockStyle.Fill; 42 this.panMain.Location = new System.Drawing.Point(46, 0); 43 this.panMain.Name = "panMain"; 44 this.panMain.Size = new System.Drawing.Size(422, 53); 45 this.panMain.TabIndex = 3; 46 // 47 // panList 48 // 49 this.panList.Anchor = System.Windows.Forms.AnchorStyles.Left; 50 this.panList.BackColor = System.Drawing.Color.Transparent; 51 this.panList.Location = new System.Drawing.Point(0, 0); 52 this.panList.Name = "panList"; 53 this.panList.Size = new System.Drawing.Size(401, 53); 54 this.panList.TabIndex = 0; 55 // 56 // panRight 57 // 58 this.panRight.BackgroundImage = global::HZH_Controls.Properties.Resources.chevron_right; 59 this.panRight.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; 60 this.panRight.Dock = System.Windows.Forms.DockStyle.Right; 61 this.panRight.Location = new System.Drawing.Point(468, 0); 62 this.panRight.Name = "panRight"; 63 this.panRight.Size = new System.Drawing.Size(46, 53); 64 this.panRight.TabIndex = 2; 65 this.panRight.Visible = false; 66 this.panRight.MouseDown += new System.Windows.Forms.MouseEventHandler(this.panRight_MouseDown); 67 // 68 // panLeft 69 // 70 this.panLeft.BackgroundImage = global::HZH_Controls.Properties.Resources.chevron_left; 71 this.panLeft.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; 72 this.panLeft.Dock = System.Windows.Forms.DockStyle.Left; 73 this.panLeft.Location = new System.Drawing.Point(0, 0); 74 this.panLeft.Name = "panLeft"; 75 this.panLeft.Size = new System.Drawing.Size(46, 53); 76 this.panLeft.TabIndex = 1; 77 this.panLeft.Visible = false; 78 this.panLeft.MouseDown += new System.Windows.Forms.MouseEventHandler(this.panLeft_MouseDown); 79 // 80 // UCHorizontalList 81 // 82 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 83 this.Controls.Add(this.panMain); 84 this.Controls.Add(this.panRight); 85 this.Controls.Add(this.panLeft); 86 this.Name = "UCHorizontalList"; 87 this.Size = new System.Drawing.Size(514, 53); 88 this.panMain.ResumeLayout(false); 89 this.ResumeLayout(false); 90 91 } 92 93 #endregion 94 95 private System.Windows.Forms.Panel panLeft; 96 private System.Windows.Forms.Panel panRight; 97 private System.Windows.Forms.Panel panMain; 98 private System.Windows.Forms.Panel panList; 99 } 100 }
用处及效果
用处:一般用着需要横向切换选项的地方,比如省份切换等
效果:
调用示例
1 List<KeyValuePair<string, string>> lstHL = new List<KeyValuePair<string, string>>(); 2 for (int i = 0; i < 30; i++) 3 { 4 lstHL.Add(new KeyValuePair<string, string>(i.ToString(), "选项" + i)); 5 } 6 7 this.ucHorizontalList1.DataSource = lstHL;
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星 星吧