前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果觉得写的还行,请点个 star 支持一下吧
NuGet
代码语言:javascript复制Install-Package HZH_Controls
目录
https://www.cnblogs.com/bfyx/p/11364884.html
用处及效果
使用分页控件效果
不使用分页控件效果
准备工作
我们需要元素控件,需要列表控件,另外为了具有更好的扩展性,元素控件实现接口,方便进行扩展
我们用到了分页控件,如果你还不了解,请移步查看
(十二)c#Winform自定义控件-分页控件
我们这里的元素控件用到圆角,故继承基类控件UCControlBase,如果不了解,请移步查看
(一)c#Winform自定义控件-基类控件
开始
添加一个接口,用来约束元素控件
代码语言:javascript复制 1 public interface IListViewItem
2 {
3 /// <summary>
4 /// 数据源
5 /// </summary>
6 object DataSource { get; set; }
7 /// <summary>
8 /// 选中项事件
9 /// </summary>
10 event EventHandler SelectedItemEvent;
11 /// <summary>
12 /// 选中处理,一般用以更改选中效果
13 /// </summary>
14 /// <param name="blnSelected">是否选中</param>
15 void SetSelected(bool blnSelected);
16 }
添加一个元素控件,命名UCListViewItem,我们这里继承基类控件UCControlBase,实现接口IListViewItem
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Drawing;
5 using System.Data;
6 using System.Linq;
7 using System.Text;
8 using System.Windows.Forms;
9
10 namespace HZH_Controls.Controls
11 {
12 [ToolboxItem(false)]
13 public partial class UCListViewItem : UCControlBase, IListViewItem
14 {
15 private object m_dataSource;
16 public object DataSource
17 {
18 get
19 {
20 return m_dataSource;
21 }
22 set
23 {
24 m_dataSource = value;
25 lblTitle.Text = value.ToString();
26 }
27 }
28
29 public event EventHandler SelectedItemEvent;
30 public UCListViewItem()
31 {
32 InitializeComponent();
33 lblTitle.MouseDown = lblTitle_MouseDown;
34 }
35
36 void lblTitle_MouseDown(object sender, MouseEventArgs e)
37 {
38 if (SelectedItemEvent != null)
39 {
40 SelectedItemEvent(this, e);
41 }
42 }
43
44 public void SetSelected(bool blnSelected)
45 {
46 if (blnSelected)
47 this.FillColor = Color.FromArgb(255, 247, 245);
48 else
49 this.FillColor = Color.White;
50 this.Refresh();
51 }
52 }
53 }
代码语言:javascript复制 1 namespace HZH_Controls.Controls
2 {
3 partial class UCListViewItem
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.SuspendLayout();
33 //
34 // lblTitle
35 //
36 this.lblTitle.Dock = System.Windows.Forms.DockStyle.Fill;
37 this.lblTitle.Location = new System.Drawing.Point(0, 0);
38 this.lblTitle.Name = "lblTitle";
39 this.lblTitle.Size = new System.Drawing.Size(107, 96);
40 this.lblTitle.TabIndex = 0;
41 this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
42 //
43 // UCListViewItem
44 //
45 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
46 this.BackColor = System.Drawing.Color.Transparent;
47 this.Controls.Add(this.lblTitle);
48 this.FillColor = System.Drawing.Color.White;
49 this.IsRadius = true;
50 this.IsShowRect = true;
51 this.Name = "UCListViewItem";
52 this.RectColor = System.Drawing.Color.FromArgb(((int)(((byte)(232)))), ((int)(((byte)(232)))), ((int)(((byte)(232)))));
53 this.Size = new System.Drawing.Size(107, 96);
54 this.ResumeLayout(false);
55
56 }
57
58 #endregion
59
60 private System.Windows.Forms.Label lblTitle;
61 }
62 }
然后需要一个列表来显示元素控件
添加一个用户控件,命名UCListView
一些属性
代码语言:javascript复制 1 int m_intCellWidth = 130;//单元格宽度
2 int m_intCellHeight = 120;//单元格高度
3
4 private Type m_itemType = typeof(UCListViewItem);
5
6 [Description("单元格类型,如果无法满足您的需求,你可以自定义单元格控件,并实现接口IListViewItem"), Category("自定义")]
7 public Type ItemType
8 {
9 get { return m_itemType; }
10 set
11 {
12 if (!typeof(IListViewItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
13 throw new Exception("单元格控件没有继承实现接口IListViewItem");
14 m_itemType = value;
15 }
16 }
17
18 private UCPagerControlBase m_page = null;
19 /// <summary>
20 /// 翻页控件
21 /// </summary>
22 [Description("翻页控件,如果UCPagerControl不满足你的需求,请自定义翻页控件并继承UCPagerControlBase"), Category("自定义")]
23 public UCPagerControlBase Page
24 {
25 get { return m_page; }
26 set
27 {
28 m_page = value;
29 if (value != null)
30 {
31 if (!typeof(IPageControl).IsAssignableFrom(value.GetType()) || !value.GetType().IsSubclassOf(typeof(UCPagerControlBase)))
32 throw new Exception("翻页控件没有继承UCPagerControlBase");
33 this.panMain.AutoScroll = false;
34 panPage.Visible = true;
35 this.Controls.SetChildIndex(panMain, 0);
36 m_page.ShowSourceChanged = m_page_ShowSourceChanged;
37 m_page.Dock = DockStyle.Fill;
38 this.panPage.Controls.Clear();
39 this.panPage.Controls.Add(m_page);
40 GetCellCount();
41 this.DataSource = m_page.GetCurrentSource();
42 }
43 else
44 {
45 this.panMain.AutoScroll = true;
46 m_page = null;
47 panPage.Visible = false;
48 }
49 }
50 }
51
52
53
54 private object m_dataSource = null;
55
56 [Description("数据源,如果使用翻页控件,请使用翻页控件的DataSource"), Category("自定义")]
57 public object DataSource
58 {
59 get { return m_dataSource; }
60 set
61 {
62 if (value == null)
63 return;
64 if (!typeof(IList).IsAssignableFrom(value.GetType()))
65 {
66 throw new Exception("数据源不是有效的数据类型,列表");
67 }
68 m_dataSource = value;
69 ReloadSource();
70 }
71 }
72
73 int m_intCellCount = 0;//单元格总数
74 [Description("单元格总数"), Category("自定义")]
75 public int CellCount
76 {
77 get { return m_intCellCount; }
78 private set
79 {
80 m_intCellCount = value;
81 if (value > 0 && m_page != null)
82 {
83 m_page.PageSize = m_intCellCount;
84 m_page.Reload();
85 }
86 }
87 }
88
89 private List<object> m_selectedSource = new List<object>();
90
91 [Description("选中的数据"), Category("自定义")]
92 public List<object> SelectedSource
93 {
94 get { return m_selectedSource; }
95 set
96 {
97 m_selectedSource = value;
98 ReloadSource();
99 }
100 }
101
102 private bool m_isMultiple = true;
103
104 [Description("是否多选"), Category("自定义")]
105 public bool IsMultiple
106 {
107 get { return m_isMultiple; }
108 set { m_isMultiple = value; }
109 }
110
111 [Description("选中项事件"), Category("自定义")]
112 public event EventHandler SelectedItemEvent;
113 public delegate void ReloadGridStyleEventHandle(int intCellCount);
114 /// <summary>
115 /// 样式改变事件
116 /// </summary>
117 [Description("样式改变事件"), Category("自定义")]
118 public event ReloadGridStyleEventHandle ReloadGridStyleEvent;
一下辅助函数
代码语言:javascript复制 1 #region 重新加载数据源
2 /// <summary>
3 /// 功能描述:重新加载数据源
4 /// 作 者:HZH
5 /// 创建日期:2019-06-27 16:47:32
6 /// 任务编号:POS
7 /// </summary>
8 public void ReloadSource()
9 {
10 ControlHelper.FreezeControl(this, true);
11 if (this.panMain.Controls.Count <= 0)
12 {
13 ReloadGridStyle();
14 }
15 if (m_dataSource == null || ((IList)m_dataSource).Count <= 0)
16 {
17 for (int i = this.panMain.Controls.Count - 1; i >= 0; i--)
18 {
19 this.panMain.Controls[i].Visible = false;
20 }
21
22 return;
23 }
24 int intCount = Math.Min(((IList)m_dataSource).Count, this.panMain.Controls.Count);
25
26 for (int i = 0; i < intCount; i )
27 {
28 ((IListViewItem)this.panMain.Controls[i]).DataSource = ((IList)m_dataSource)[i];
29 if (m_selectedSource.Contains(((IList)m_dataSource)[i]))
30 {
31 ((IListViewItem)this.panMain.Controls[i]).SetSelected(true);
32 }
33 else
34 {
35 ((IListViewItem)this.panMain.Controls[i]).SetSelected(false);
36 }
37 this.panMain.Controls[i].Visible = true;
38 }
39
40 for (int i = this.panMain.Controls.Count - 1; i >= intCount; i--)
41 {
42 if (this.panMain.Controls[i].Visible)
43 this.panMain.Controls[i].Visible = false;
44 }
45 ControlHelper.FreezeControl(this, false);
46 }
47 #endregion
48
49 #region 刷新表格
50 /// <summary>
51 /// 功能描述:刷新表格样式
52 /// 作 者:HZH
53 /// 创建日期:2019-06-27 16:35:25
54 /// 任务编号:POS
55 /// </summary>
56 public void ReloadGridStyle()
57 {
58 Form frmMain = this.FindForm();
59 if (frmMain != null && !frmMain.IsDisposed && frmMain.Visible && this.Visible)
60 {
61 GetCellCount();
62 try
63 {
64 ControlHelper.FreezeControl(this, true);
65 if (this.panMain.Controls.Count < m_intCellCount)
66 {
67 int intControlsCount = this.panMain.Controls.Count;
68 for (int i = 0; i < m_intCellCount - intControlsCount; i )
69 {
70 Control uc = (Control)Activator.CreateInstance(m_itemType);
71 uc.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
72
73 (uc as IListViewItem).SelectedItemEvent = UCListView_SelectedItemEvent;
74 uc.Visible = false;
75 this.panMain.Controls.Add(uc);
76 }
77 }
78 else if (this.panMain.Controls.Count > m_intCellCount)
79 {
80 int intControlsCount = this.panMain.Controls.Count;
81 for (int i = intControlsCount - 1; i > m_intCellCount - 1; i--)
82 {
83 this.panMain.Controls.RemoveAt(i);
84 }
85 }
86 foreach (Control item in this.panMain.Controls)
87 {
88 item.Size = new Size(m_intCellWidth, m_intCellHeight);
89 }
90 }
91 finally
92 {
93 ControlHelper.FreezeControl(this, false);
94 }
95 if (ReloadGridStyleEvent != null)
96 {
97 ReloadGridStyleEvent(m_intCellCount);
98 }
99 }
100
101 }
102
103 void UCListView_SelectedItemEvent(object sender, EventArgs e)
104 {
105 var selectedItem = sender as IListViewItem;
106
107 if (m_selectedSource.Contains(selectedItem.DataSource))
108 {
109 m_selectedSource.Remove(selectedItem.DataSource);
110 selectedItem.SetSelected(false);
111 }
112 else
113 {
114 if (m_isMultiple)
115 {
116 m_selectedSource.Add(selectedItem.DataSource);
117 selectedItem.SetSelected(true);
118 }
119 else
120 {
121 if (m_selectedSource.Count > 0)
122 {
123 int intCount = Math.Min(((IList)m_dataSource).Count, this.panMain.Controls.Count);
124 for (int i = 0; i < intCount; i )
125 {
126 var item = ((IListViewItem)this.panMain.Controls[i]);
127 if (m_selectedSource.Contains(item.DataSource))
128 {
129 item.SetSelected(false);
130 break;
131 }
132 }
133 }
134
135 m_selectedSource = new List<object>() { selectedItem.DataSource };
136 selectedItem.SetSelected(true);
137
138 }
139 }
140
141 if (SelectedItemEvent != null)
142 {
143 SelectedItemEvent(sender, e);
144 }
145 }
146 #endregion
147
148 #region 获取cell总数
149 /// <summary>
150 /// 功能描述:获取cell总数
151 /// 作 者:HZH
152 /// 创建日期:2019-06-27 16:28:58
153 /// 任务编号:POS
154 /// </summary>
155 private void GetCellCount()
156 {
157 if (this.panMain.Width == 0)
158 return;
159 Control item = (Control)Activator.CreateInstance(m_itemType);
160
161
162 int intXCount = (this.panMain.Width - 10) / (item.Width 10);
163 m_intCellWidth = item.Width ((this.panMain.Width - 10) % (item.Width 10)) / intXCount;
164
165 int intYCount = (this.panMain.Height - 10) / (item.Height 10);
166 m_intCellHeight = item.Height ((this.panMain.Height - 10) % (item.Height 10)) / intYCount;
167 int intCount = intXCount * intYCount;
168
169 if (Page == null)
170 {
171 if (((IList)m_dataSource).Count > intCount)
172 {
173 intXCount = (this.panMain.Width - 10 - 20) / (item.Width 10);
174 m_intCellWidth = item.Width ((this.panMain.Width - 10 - 20) % (item.Width 10)) / intXCount;
175 }
176 intCount = Math.Max(intCount, ((IList)m_dataSource).Count);
177 }
178
179 CellCount = intCount;
180 }
181 #endregion
一些事件
代码语言:javascript复制 private void panMain_Resize(object sender, EventArgs e)
{
ReloadGridStyle();
}
void m_page_ShowSourceChanged(object currentSource)
{
this.DataSource = currentSource;
}
你会发现,有个ItemType属性,这个用来定义列表呈现那种子元素,这么用的好处就是,当你觉得我写的这个元素控件UCListViewItem并不能满足你需求的时候,你可以添加一个自定义控件,并实现接口IListViewItem,然后将你自定义的控件指定给这个属性,列表就会呈现出来了,是不是很方便,列表会自动根据你的元素控件的大小来适量调整来填充到列表中的。
还有一个Page属性,这个是用来表示用哪个分页控件,当然你也可以不用,我已经提供了2种分页控件,如果你觉得还是不满足你的话,去参考分页控件那个文章,自己添加一个分页控件吧。
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星星吧