入行已经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 = "分类名称\r\n分类名称";
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;