前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果觉得写的还行,请点个 star 支持一下吧
目录
https://blog.csdn.net/kwwwvagaa/article/details/100586547
准备工作
表格控件将拆分为2部分,1:行元素控件,2:列表控件
为了具有更好的扩展性,更加的open,使用接口对行元素进行约束,当行样式或功能不满足你的需求的时候,可以自定义一个行元素,实现接口控件,然后将类型指定给列表控件即可
表格控件用到了分页控件,如果你还没有对分页控件进行了解,请移步查看
开始
定义一些辅助东西
1 public class DataGridViewCellEntity
2 {
3 public string Title { get; set; }
4 public int Width { get; set; }
5 public System.Windows.Forms.SizeType WidthType { get; set; }
6
7 }
1 public class DataGridViewEventArgs : EventArgs
2 {
3 public Control CellControl { get; set; }
4 public int CellIndex { get; set; }
5 public int RowIndex { get; set; }
6
7
8 }
1 [Serializable]
2 [ComVisible(true)]
3 public delegate void DataGridViewEventHandler(object sender, DataGridViewEventArgs e);
1 public class DataGridViewColumnEntity
2 {
3 public string HeadText { get; set; }
4 public int Width { get; set; }
5 public System.Windows.Forms.SizeType WidthType { get; set; }
6 public string DataField { get; set; }
7 public Func<object, string> Format { get; set; }
8 }
定义行接口
1 public interface IDataGridViewRow
2 {
3 /// <summary>
4 /// CheckBox选中事件
5 /// </summary>
6 event DataGridViewEventHandler CheckBoxChangeEvent;
7 /// <summary>
8 /// 点击单元格事件
9 /// </summary>
10 event DataGridViewEventHandler CellClick;
11 /// <summary>
12 /// 数据源改变事件
13 /// </summary>
14 event DataGridViewEventHandler SourceChanged;
15 /// <summary>
16 /// 列参数,用于创建列数和宽度
17 /// </summary>
18 List<DataGridViewColumnEntity> Columns { get; set; }
19 bool IsShowCheckBox { get; set; }
20 /// <summary>
21 /// 是否选中
22 /// </summary>
23 bool IsChecked { get; set; }
24
25 /// <summary>
26 /// 数据源
27 /// </summary>
28 object DataSource { get; set; }
29 /// <summary>
30 /// 添加单元格元素,仅做添加控件操作,不做数据绑定,数据绑定使用BindingCells
31 /// </summary>
32 void ReloadCells();
33 /// <summary>
34 /// 绑定数据到Cell
35 /// </summary>
36 /// <param name="intIndex">cell下标</param>
37 /// <returns>返回true则表示已处理过,否则将进行默认绑定(通常只针对有Text值的控件)</returns>
38 void BindingCellData();
39 /// <summary>
40 /// 设置选中状态,通常为设置颜色即可
41 /// </summary>
42 /// <param name="blnSelected">是否选中</param>
43 void SetSelect(bool blnSelected);
44 }
创建行控件
添加一个用户控件,命名UCDataGridViewRow,实现接口IDataGridViewRow
属性
1 #region 属性
2 public event DataGridViewEventHandler CheckBoxChangeEvent;
3
4 public event DataGridViewEventHandler CellClick;
5
6 public event DataGridViewEventHandler SourceChanged;
7
8 public List<DataGridViewColumnEntity> Columns
9 {
10 get;
11 set;
12 }
13
14 public object DataSource
15 {
16 get;
17 set;
18 }
19
20 public bool IsShowCheckBox
21 {
22 get;
23 set;
24 }
25 private bool m_isChecked;
26 public bool IsChecked
27 {
28 get
29 {
30 return m_isChecked;
31 }
32
33 set
34 {
35 if (m_isChecked != value)
36 {
37 m_isChecked = value;
38 (this.panCells.Controls.Find("check", false)[0] as UCCheckBox).Checked = value;
39 }
40 }
41 }
42
43
44 #endregion
实现接口
1 public void BindingCellData()
2 {
3 for (int i = 0; i < Columns.Count; i++)
4 {
5 DataGridViewColumnEntity com = Columns[i];
6 var cs = this.panCells.Controls.Find("lbl_" + com.DataField, false);
7 if (cs != null && cs.Length > 0)
8 {
9 var pro = DataSource.GetType().GetProperty(com.DataField);
10 if (pro != null)
11 {
12 var value = pro.GetValue(DataSource, null);
13 if (com.Format != null)
14 {
15 cs[0].Text = com.Format(value);
16 }
17 else
18 {
19 cs[0].Text = value.ToStringExt();
20 }
21 }
22 }
23 }
24 }
25
26 public void SetSelect(bool blnSelected)
27 {
28 if (blnSelected)
29 {
30 this.BackColor = Color.FromArgb(255, 247, 245);
31 }
32 else
33 {
34 this.BackColor = Color.Transparent;
35 }
36 }
37
38 public void ReloadCells()
39 {
40 try
41 {
42 ControlHelper.FreezeControl(this, true);
43 this.panCells.Controls.Clear();
44 this.panCells.ColumnStyles.Clear();
45
46 int intColumnsCount = Columns.Count();
47 if (Columns != null && intColumnsCount > 0)
48 {
49 if (IsShowCheckBox)
50 {
51 intColumnsCount++;
52 }
53 this.panCells.ColumnCount = intColumnsCount;
54 for (int i = 0; i < intColumnsCount; i++)
55 {
56 Control c = null;
57 if (i == 0 && IsShowCheckBox)
58 {
59 this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(SizeType.Absolute, 30F));
60
61 UCCheckBox box = new UCCheckBox();
62 box.Name = "check";
63 box.TextValue = "";
64 box.Size = new Size(30, 30);
65 box.Dock = DockStyle.Fill;
66 box.CheckedChangeEvent += (a, b) =>
67 {
68 IsChecked = box.Checked;
69 if (CheckBoxChangeEvent != null)
70 {
71 CheckBoxChangeEvent(a, new DataGridViewEventArgs()
72 {
73 CellControl = box,
74 CellIndex = 0
75 });
76 }
77 };
78 c = box;
79 }
80 else
81 {
82 var item = Columns[i - (IsShowCheckBox ? 1 : 0)];
83 this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(item.WidthType, item.Width));
84
85 Label lbl = new Label();
86 lbl.Tag = i - (IsShowCheckBox ? 1 : 0);
87 lbl.Name = "lbl_" + item.DataField;
88 lbl.Font = new Font("微软雅黑", 12);
89 lbl.ForeColor = Color.Black;
90 lbl.AutoSize = false;
91 lbl.Dock = DockStyle.Fill;
92 lbl.TextAlign = ContentAlignment.MiddleCenter;
93 lbl.MouseDown += (a, b) =>
94 {
95 Item_MouseDown(a, b);
96 };
97 c = lbl;
98 }
99 this.panCells.Controls.Add(c, i, 0);
100 }
101
102 }
103 }
104 finally
105 {
106 ControlHelper.FreezeControl(this, false);
107 }
108 }
节点选中事件
1 void Item_MouseDown(object sender, MouseEventArgs e)
2 {
3 if (CellClick != null)
4 {
5 CellClick(sender, new DataGridViewEventArgs()
6 {
7 CellControl = this,
8 CellIndex = (sender as Control).Tag.ToInt()
9 });
10 }
11 }
完整的代码
View Code
View Code
接下来就是列表控件了
添加一个用户控件,命名UCDataGridView
属性
1 #region 属性
2 private Font m_headFont = new Font("微软雅黑", 12F);
3 /// <summary>
4 /// 标题字体
5 /// </summary>
6 [Description("标题字体"), Category("自定义")]
7 public Font HeadFont
8 {
9 get { return m_headFont; }
10 set { m_headFont = value; }
11 }
12 private Color m_headTextColor = Color.Black;
13 /// <summary>
14 /// 标题字体颜色
15 /// </summary>
16 [Description("标题文字颜色"), Category("自定义")]
17 public Color HeadTextColor
18 {
19 get { return m_headTextColor; }
20 set { m_headTextColor = value; }
21 }
22
23 private bool m_isShowHead = true;
24 /// <summary>
25 /// 是否显示标题
26 /// </summary>
27 [Description("是否显示标题"), Category("自定义")]
28 public bool IsShowHead
29 {
30 get { return m_isShowHead; }
31 set
32 {
33 m_isShowHead = value;
34 panHead.Visible = value;
35 if (m_page != null)
36 {
37 ResetShowCount();
38 m_page.PageSize = m_showCount;
39 }
40 }
41 }
42 private int m_headHeight = 40;
43 /// <summary>
44 /// 标题高度
45 /// </summary>
46 [Description("标题高度"), Category("自定义")]
47 public int HeadHeight
48 {
49 get { return m_headHeight; }
50 set
51 {
52 m_headHeight = value;
53 panHead.Height = value;
54 }
55 }
56
57 private bool m_isShowCheckBox = false;
58 /// <summary>
59 /// 是否显示复选框
60 /// </summary>
61 [Description("是否显示选择框"), Category("自定义")]
62 public bool IsShowCheckBox
63 {
64 get { return m_isShowCheckBox; }
65 set
66 {
67 if (value != m_isShowCheckBox)
68 {
69 m_isShowCheckBox = value;
70 LoadColumns();
71 }
72 }
73 }
74
75 private int m_rowHeight = 40;
76 /// <summary>
77 /// 行高
78 /// </summary>
79 [Description("数据行高"), Category("自定义")]
80 public int RowHeight
81 {
82 get { return m_rowHeight; }
83 set { m_rowHeight = value; }
84 }
85
86 private int m_showCount = 0;
87 /// <summary>
88 ///
89 /// </summary>
90 [Description("可显示个数"), Category("自定义")]
91 public int ShowCount
92 {
93 get { return m_showCount; }
94 private set
95 {
96 m_showCount = value;
97 if (m_page != null)
98 {
99 m_page.PageSize = value;
100 }
101 }
102 }
103
104 private List<DataGridViewColumnEntity> m_columns;
105 /// <summary>
106 /// 列
107 /// </summary>
108 [Description("列"), Category("自定义")]
109 public List<DataGridViewColumnEntity> Columns
110 {
111 get { return m_columns; }
112 set
113 {
114 m_columns = value;
115 LoadColumns();
116 }
117 }
118
119 private object m_dataSource;
120 /// <summary>
121 /// 数据源,支持列表或table,如果使用翻页控件,请使用翻页控件的DataSource
122 /// </summary>
123 [Description("数据源,支持列表或table,如果使用翻页控件,请使用翻页控件的DataSource"), Category("自定义")]
124 public object DataSource
125 {
126 get { return m_dataSource; }
127 set
128 {
129 if (value == null)
130 return;
131 if (!(m_dataSource is DataTable) && (!typeof(IList).IsAssignableFrom(value.GetType())))
132 {
133 throw new Exception("数据源不是有效的数据类型,请使用Datatable或列表");
134 }
135
136 m_dataSource = value;
137 ReloadSource();
138 }
139 }
140
141 public List<IDataGridViewRow> Rows { get; private set; }
142
143 private Type m_rowType = typeof(UCDataGridViewRow);
144 /// <summary>
145 /// 行元素类型,默认UCDataGridViewItem
146 /// </summary>
147 [Description("行控件类型,默认UCDataGridViewRow,如果不满足请自定义行控件实现接口IDataGridViewRow"), Category("自定义")]
148 public Type RowType
149 {
150 get { return m_rowType; }
151 set
152 {
153 if (value == null)
154 return;
155 if (!typeof(IDataGridViewRow).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
156 throw new Exception("行控件没有实现IDataGridViewRow接口");
157 m_rowType = value;
158 }
159 }
160 IDataGridViewRow m_selectRow = null;
161 /// <summary>
162 /// 选中的节点
163 /// </summary>
164 [Description("选中行"), Category("自定义")]
165 public IDataGridViewRow SelectRow
166 {
167 get { return m_selectRow; }
168 private set { m_selectRow = value; }
169 }
170
171
172 /// <summary>
173 /// 选中的行,如果显示CheckBox,则以CheckBox选中为准
174 /// </summary>
175 [Description("选中的行,如果显示CheckBox,则以CheckBox选中为准"), Category("自定义")]
176 public List<IDataGridViewRow> SelectRows
177 {
178 get
179 {
180 if (m_isShowCheckBox)
181 {
182 return Rows.FindAll(p => p.IsChecked);
183 }
184 else
185 return new List<IDataGridViewRow>() { m_selectRow };
186 }
187 }
188
189
190 private UCPagerControlBase m_page = null;
191 /// <summary>
192 /// 翻页控件
193 /// </summary>
194 [Description("翻页控件,如果UCPagerControl不满足你的需求,请自定义翻页控件并继承UCPagerControlBase"), Category("自定义")]
195 public UCPagerControlBase Page
196 {
197 get { return m_page; }
198 set
199 {
200 m_page = value;
201 if (value != null)
202 {
203 if (!typeof(IPageControl).IsAssignableFrom(value.GetType()) || !value.GetType().IsSubclassOf(typeof(UCPagerControlBase)))
204 throw new Exception("翻页控件没有继承UCPagerControlBase");
205 panPage.Visible = value != null;
206 m_page.ShowSourceChanged += page_ShowSourceChanged;
207 m_page.Dock = DockStyle.Fill;
208 this.panPage.Controls.Clear();
209 this.panPage.Controls.Add(m_page);
210 ResetShowCount();
211 m_page.PageSize = ShowCount;
212 this.DataSource = m_page.GetCurrentSource();
213 }
214 else
215 {
216 m_page = null;
217 }
218 }
219 }
220
221 void page_ShowSourceChanged(object currentSource)
222 {
223 this.DataSource = currentSource;
224 }
225
226 #region 事件
227 [Description("选中标题选择框事件"), Category("自定义")]
228 public EventHandler HeadCheckBoxChangeEvent;
229 [Description("标题点击事件"), Category("自定义")]
230 public EventHandler HeadColumnClickEvent;
231 [Description("项点击事件"), Category("自定义")]
232 public event DataGridViewEventHandler ItemClick;
233 [Description("数据源改变事件"), Category("自定义")]
234 public event DataGridViewEventHandler SourceChanged;
235 #endregion
236 #endregion
一些私有的方法
1 #region 私有方法
2 #region 加载column
3 /// <summary>
4 /// 功能描述:加载column
5 /// 作 者:HZH
6 /// 创建日期:2019-08-08 17:51:50
7 /// 任务编号:POS
8 /// </summary>
9 private void LoadColumns()
10 {
11 try
12 {
13 if (DesignMode)
14 { return; }
15
16 ControlHelper.FreezeControl(this.panHead, true);
17 this.panColumns.Controls.Clear();
18 this.panColumns.ColumnStyles.Clear();
19
20 if (m_columns != null && m_columns.Count() > 0)
21 {
22 int intColumnsCount = m_columns.Count();
23 if (m_isShowCheckBox)
24 {
25 intColumnsCount++;
26 }
27 this.panColumns.ColumnCount = intColumnsCount;
28 for (int i = 0; i < intColumnsCount; i++)
29 {
30 Control c = null;
31 if (i == 0 && m_isShowCheckBox)
32 {
33 this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(SizeType.Absolute, 30F));
34
35 UCCheckBox box = new UCCheckBox();
36 box.TextValue = "";
37 box.Size = new Size(30, 30);
38 box.CheckedChangeEvent += (a, b) =>
39 {
40 Rows.ForEach(p => p.IsChecked = box.Checked);
41 if (HeadCheckBoxChangeEvent != null)
42 {
43 HeadCheckBoxChangeEvent(a, b);
44 }
45 };
46 c = box;
47 }
48 else
49 {
50 var item = m_columns[i - (m_isShowCheckBox ? 1 : 0)];
51 this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(item.WidthType, item.Width));
52 Label lbl = new Label();
53 lbl.Name = "dgvColumns_" + i;
54 lbl.Text = item.HeadText;
55 lbl.Font = m_headFont;
56 lbl.ForeColor = m_headTextColor;
57 lbl.TextAlign = ContentAlignment.MiddleCenter;
58 lbl.AutoSize = false;
59 lbl.Dock = DockStyle.Fill;
60 lbl.MouseDown += (a, b) =>
61 {
62 if (HeadColumnClickEvent != null)
63 {
64 HeadColumnClickEvent(a, b);
65 }
66 };
67 c = lbl;
68 }
69 this.panColumns.Controls.Add(c, i, 0);
70 }
71
72 }
73 }
74 finally
75 {
76 ControlHelper.FreezeControl(this.panHead, false);
77 }
78 }
79 #endregion
80
81 /// <summary>
82 /// 功能描述:获取显示个数
83 /// 作 者:HZH
84 /// 创建日期:2019-03-05 10:02:58
85 /// 任务编号:POS
86 /// </summary>
87 /// <returns>返回值</returns>
88 private void ResetShowCount()
89 {
90 if (DesignMode)
91 { return; }
92 ShowCount = this.panRow.Height / (m_rowHeight);
93 int intCha = this.panRow.Height % (m_rowHeight);
94 m_rowHeight += intCha / ShowCount;
95 }
96 #endregion
几个事件
1 #region 事件
2 void RowSourceChanged(object sender, DataGridViewEventArgs e)
3 {
4 if (SourceChanged != null)
5 SourceChanged(sender, e);
6 }
7 private void SetSelectRow(Control item, DataGridViewEventArgs e)
8 {
9 try
10 {
11 ControlHelper.FreezeControl(this, true);
12 if (item == null)
13 return;
14 if (item.Visible == false)
15 return;
16 this.FindForm().ActiveControl = this;
17 this.FindForm().ActiveControl = item;
18 if (m_selectRow != null)
19 {
20 if (m_selectRow == item)
21 return;
22 m_selectRow.SetSelect(false);
23 }
24 m_selectRow = item as IDataGridViewRow;
25 m_selectRow.SetSelect(true);
26 if (ItemClick != null)
27 {
28 ItemClick(item, e);
29 }
30 if (this.panRow.Controls.Count > 0)
31 {
32 if (item.Location.Y < 0)
33 {
34 this.panRow.AutoScrollPosition = new Point(0, Math.Abs(this.panRow.Controls[this.panRow.Controls.Count - 1].Location.Y) + item.Location.Y);
35 }
36 else if (item.Location.Y + m_rowHeight > this.panRow.Height)
37 {
38 this.panRow.AutoScrollPosition = new Point(0, Math.Abs(this.panRow.AutoScrollPosition.Y) + item.Location.Y - this.panRow.Height + m_rowHeight);
39 }
40 }
41 }
42 finally
43 {
44 ControlHelper.FreezeControl(this, false);
45 }
46 }
47 private void UCDataGridView_Resize(object sender, EventArgs e)
48 {
49 ResetShowCount();
50 ReloadSource();
51 }
52 #endregion
对外公开的函数
1 #region 公共函数
2 /// <summary>
3 /// 刷新数据
4 /// </summary>
5 public void ReloadSource()
6 {
7 if (DesignMode)
8 { return; }
9 try
10 {
11 if (m_columns == null || m_columns.Count <= 0)
12 return;
13
14 ControlHelper.FreezeControl(this.panRow, true);
15 this.panRow.Controls.Clear();
16 Rows = new List<IDataGridViewRow>();
17 if (m_dataSource != null)
18 {
19 int intIndex = 0;
20 Control lastItem = null;
21
22 int intSourceCount = 0;
23 if (m_dataSource is DataTable)
24 {
25 intSourceCount = (m_dataSource as DataTable).Rows.Count;
26 }
27 else if (typeof(IList).IsAssignableFrom(m_dataSource.GetType()))
28 {
29 intSourceCount = (m_dataSource as IList).Count;
30 }
31
32 foreach (Control item in this.panRow.Controls)
33 {
34
35
36 if (intIndex >= intSourceCount)
37 {
38 item.Visible = false;
39 }
40 else
41 {
42 var row = (item as IDataGridViewRow);
43 row.IsShowCheckBox = m_isShowCheckBox;
44 if (m_dataSource is DataTable)
45 {
46 row.DataSource = (m_dataSource as DataTable).Rows[intIndex];
47 }
48 else
49 {
50 row.DataSource = (m_dataSource as IList)[intIndex];
51 }
52 row.BindingCellData();
53 item.Height = m_rowHeight;
54 item.Visible = true;
55 item.BringToFront();
56 if (lastItem == null)
57 lastItem = item;
58 Rows.Add(row);
59 }
60 intIndex++;
61 }
62
63 if (intIndex < intSourceCount)
64 {
65 for (int i = intIndex; i < intSourceCount; i++)
66 {
67 IDataGridViewRow row = (IDataGridViewRow)Activator.CreateInstance(m_rowType);
68 if (m_dataSource is DataTable)
69 {
70 row.DataSource = (m_dataSource as DataTable).Rows[i];
71 }
72 else
73 {
74 row.DataSource = (m_dataSource as IList)[i];
75 }
76 row.Columns = m_columns;
77 List<Control> lstCells = new List<Control>();
78 row.IsShowCheckBox = m_isShowCheckBox;
79 row.ReloadCells();
80 row.BindingCellData();
81
82
83 Control rowControl = (row as Control);
84 rowControl.Height = m_rowHeight;
85 this.panRow.Controls.Add(rowControl);
86 rowControl.Dock = DockStyle.Top;
87 row.CellClick += (a, b) => { SetSelectRow(rowControl, b); };
88 row.CheckBoxChangeEvent += (a, b) => { SetSelectRow(rowControl, b); };
89 row.SourceChanged += RowSourceChanged;
90 rowControl.BringToFront();
91 Rows.Add(row);
92
93 if (lastItem == null)
94 lastItem = rowControl;
95 }
96 }
97 if (lastItem != null && intSourceCount == m_showCount)
98 {
99 lastItem.Height = this.panRow.Height - (m_showCount - 1) * m_rowHeight;
100 }
101 }
102 }
103 finally
104 {
105 ControlHelper.FreezeControl(this.panRow, false);
106 }
107 }
108
109
110 /// <summary>
111 /// 快捷键
112 /// </summary>
113 /// <param name="msg"></param>
114 /// <param name="keyData"></param>
115 /// <returns></returns>
116 protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
117 {
118 if (keyData == Keys.Up)
119 {
120 Previous();
121 }
122 else if (keyData == Keys.Down)
123 {
124 Next();
125 }
126 else if (keyData == Keys.Home)
127 {
128 First();
129 }
130 else if (keyData == Keys.End)
131 {
132 End();
133 }
134 return base.ProcessCmdKey(ref msg, keyData);
135 }
136 /// <summary>
137 /// 选中第一个
138 /// </summary>
139 public void First()
140 {
141 if (Rows == null || Rows.Count <= 0)
142 return;
143 Control c = null;
144 c = (Rows[0] as Control);
145 SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = 0 });
146 }
147 /// <summary>
148 /// 选中上一个
149 /// </summary>
150 public void Previous()
151 {
152 if (Rows == null || Rows.Count <= 0)
153 return;
154 Control c = null;
155
156 int index = Rows.IndexOf(m_selectRow);
157 if (index - 1 >= 0)
158 {
159 c = (Rows[index - 1] as Control);
160 SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = index - 1 });
161 }
162 }
163 /// <summary>
164 /// 选中下一个
165 /// </summary>
166 public void Next()
167 {
168 if (Rows == null || Rows.Count <= 0)
169 return;
170 Control c = null;
171
172 int index = Rows.IndexOf(m_selectRow);
173 if (index + 1 < Rows.Count)
174 {
175 c = (Rows[index + 1] as Control);
176 SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = index + 1 });
177 }
178 }
179 /// <summary>
180 /// 选中最后一个
181 /// </summary>
182 public void End()
183 {
184 if (Rows == null || Rows.Count <= 0)
185 return;
186 Control c = null;
187 c = (Rows[Rows.Count - 1] as Control);
188 SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = Rows.Count - 1 });
189 }
190
191 #endregion
完整代码
// 版权所有 黄正辉 交流群:568015492 QQ:623128629
// 文件名称:UCDataGridView.cs
// 创建日期:2019-08-15 15:59:25
// 功能描述:DataGridView
// 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
namespace HZH_Controls.Controls
{
public partial class UCDataGridView : UserControl
{
#region 属性
private Font m_headFont = new Font("微软雅黑", 12F);
/// <summary>
/// 标题字体
/// </summary>
[Description("标题字体"), Category("自定义")]
public Font HeadFont
{
get { return m_headFont; }
set { m_headFont = value; }
}
private Color m_headTextColor = Color.Black;
/// <summary>
/// 标题字体颜色
/// </summary>
[Description("标题文字颜色"), Category("自定义")]
public Color HeadTextColor
{
get { return m_headTextColor; }
set { m_headTextColor = value; }
}
private bool m_isShowHead = true;
/// <summary>
/// 是否显示标题
/// </summary>
[Description("是否显示标题"), Category("自定义")]
public bool IsShowHead
{
get { return m_isShowHead; }
set
{
m_isShowHead = value;
panHead.Visible = value;
if (m_page != null)
{
ResetShowCount();
m_page.PageSize = m_showCount;
}
}
}
private int m_headHeight = 40;
/// <summary>
/// 标题高度
/// </summary>
[Description("标题高度"), Category("自定义")]
public int HeadHeight
{
get { return m_headHeight; }
set
{
m_headHeight = value;
panHead.Height = value;
}
}
private bool m_isShowCheckBox = false;
/// <summary>
/// 是否显示复选框
/// </summary>
[Description("是否显示选择框"), Category("自定义")]
public bool IsShowCheckBox
{
get { return m_isShowCheckBox; }
set
{
if (value != m_isShowCheckBox)
{
m_isShowCheckBox = value;
LoadColumns();
}
}
}
private int m_rowHeight = 40;
/// <summary>
/// 行高
/// </summary>
[Description("数据行高"), Category("自定义")]
public int RowHeight
{
get { return m_rowHeight; }
set { m_rowHeight = value; }
}
private int m_showCount = 0;
/// <summary>
///
/// </summary>
[Description("可显示个数"), Category("自定义")]
public int ShowCount
{
get { return m_showCount; }
private set
{
m_showCount = value;
if (m_page != null)
{
m_page.PageSize = value;
}
}
}
private List<DataGridViewColumnEntity> m_columns;
/// <summary>
/// 列
/// </summary>
[Description("列"), Category("自定义")]
public List<DataGridViewColumnEntity> Columns
{
get { return m_columns; }
set
{
m_columns = value;
LoadColumns();
}
}
private object m_dataSource;
/// <summary>
/// 数据源,支持列表或table,如果使用翻页控件,请使用翻页控件的DataSource
/// </summary>
[Description("数据源,支持列表或table,如果使用翻页控件,请使用翻页控件的DataSource"), Category("自定义")]
public object DataSource
{
get { return m_dataSource; }
set
{
if (value == null)
return;
if (!(m_dataSource is DataTable) && (!typeof(IList).IsAssignableFrom(value.GetType())))
{
throw new Exception("数据源不是有效的数据类型,请使用Datatable或列表");
}
m_dataSource = value;
ReloadSource();
}
}
public List<IDataGridViewRow> Rows { get; private set; }
private Type m_rowType = typeof(UCDataGridViewRow);
/// <summary>
/// 行元素类型,默认UCDataGridViewItem
/// </summary>
[Description("行控件类型,默认UCDataGridViewRow,如果不满足请自定义行控件实现接口IDataGridViewRow"), Category("自定义")]
public Type RowType
{
get { return m_rowType; }
set
{
if (value == null)
return;
if (!typeof(IDataGridViewRow).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
throw new Exception("行控件没有实现IDataGridViewRow接口");
m_rowType = value;
}
}
IDataGridViewRow m_selectRow = null;
/// <summary>
/// 选中的节点
/// </summary>
[Description("选中行"), Category("自定义")]
public IDataGridViewRow SelectRow
{
get { return m_selectRow; }
private set { m_selectRow = value; }
}
/// <summary>
/// 选中的行,如果显示CheckBox,则以CheckBox选中为准
/// </summary>
[Description("选中的行,如果显示CheckBox,则以CheckBox选中为准"), Category("自定义")]
public List<IDataGridViewRow> SelectRows
{
get
{
if (m_isShowCheckBox)
{
return Rows.FindAll(p => p.IsChecked);
}
else
return new List<IDataGridViewRow>() { m_selectRow };
}
}
private UCPagerControlBase m_page = null;
/// <summary>
/// 翻页控件
/// </summary>
[Description("翻页控件,如果UCPagerControl不满足你的需求,请自定义翻页控件并继承UCPagerControlBase"), Category("自定义")]
public UCPagerControlBase Page
{
get { return m_page; }
set
{
m_page = value;
if (value != null)
{
if (!typeof(IPageControl).IsAssignableFrom(value.GetType()) || !value.GetType().IsSubclassOf(typeof(UCPagerControlBase)))
throw new Exception("翻页控件没有继承UCPagerControlBase");
panPage.Visible = value != null;
m_page.ShowSourceChanged += page_ShowSourceChanged;
m_page.Dock = DockStyle.Fill;
this.panPage.Controls.Clear();
this.panPage.Controls.Add(m_page);
ResetShowCount();
m_page.PageSize = ShowCount;
this.DataSource = m_page.GetCurrentSource();
}
else
{
m_page = null;
}
}
}
void page_ShowSourceChanged(object currentSource)
{
this.DataSource = currentSource;
}
#region 事件
[Description("选中标题选择框事件"), Category("自定义")]
public EventHandler HeadCheckBoxChangeEvent;
[Description("标题点击事件"), Category("自定义")]
public EventHandler HeadColumnClickEvent;
[Description("项点击事件"), Category("自定义")]
public event DataGridViewEventHandler ItemClick;
[Description("数据源改变事件"), Category("自定义")]
public event DataGridViewEventHandler SourceChanged;
#endregion
#endregion
public UCDataGridView()
{
InitializeComponent();
}
#region 私有方法
#region 加载column
/// <summary>
/// 功能描述:加载column
/// 作 者:HZH
/// 创建日期:2019-08-08 17:51:50
/// 任务编号:POS
/// </summary>
private void LoadColumns()
{
try
{
if (DesignMode)
{ return; }
ControlHelper.FreezeControl(this.panHead, true);
this.panColumns.Controls.Clear();
this.panColumns.ColumnStyles.Clear();
if (m_columns != null && m_columns.Count() > 0)
{
int intColumnsCount = m_columns.Count();
if (m_isShowCheckBox)
{
intColumnsCount++;
}
this.panColumns.ColumnCount = intColumnsCount;
for (int i = 0; i < intColumnsCount; i++)
{
Control c = null;
if (i == 0 && m_isShowCheckBox)
{
this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(SizeType.Absolute, 30F));
UCCheckBox box = new UCCheckBox();
box.TextValue = "";
box.Size = new Size(30, 30);
box.CheckedChangeEvent += (a, b) =>
{
Rows.ForEach(p => p.IsChecked = box.Checked);
if (HeadCheckBoxChangeEvent != null)
{
HeadCheckBoxChangeEvent(a, b);
}
};
c = box;
}
else
{
var item = m_columns[i - (m_isShowCheckBox ? 1 : 0)];
this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(item.WidthType, item.Width));
Label lbl = new Label();
lbl.Name = "dgvColumns_" + i;
lbl.Text = item.HeadText;
lbl.Font = m_headFont;
lbl.ForeColor = m_headTextColor;
lbl.TextAlign = ContentAlignment.MiddleCenter;
lbl.AutoSize = false;
lbl.Dock = DockStyle.Fill;
lbl.MouseDown += (a, b) =>
{
if (HeadColumnClickEvent != null)
{
HeadColumnClickEvent(a, b);
}
};
c = lbl;
}
this.panColumns.Controls.Add(c, i, 0);
}
}
}
finally
{
ControlHelper.FreezeControl(this.panHead, false);
}
}
#endregion
/// <summary>
/// 功能描述:获取显示个数
/// 作 者:HZH
/// 创建日期:2019-03-05 10:02:58
/// 任务编号:POS
/// </summary>
/// <returns>返回值</returns>
private void ResetShowCount()
{
if (DesignMode)
{ return; }
ShowCount = this.panRow.Height / (m_rowHeight);
int intCha = this.panRow.Height % (m_rowHeight);
m_rowHeight += intCha / ShowCount;
}
#endregion
#region 公共函数
/// <summary>
/// 刷新数据
/// </summary>
public void ReloadSource()
{
if (DesignMode)
{ return; }
try
{
if (m_columns == null || m_columns.Count <= 0)
return;
ControlHelper.FreezeControl(this.panRow, true);
this.panRow.Controls.Clear();
Rows = new List<IDataGridViewRow>();
if (m_dataSource != null)
{
int intIndex = 0;
Control lastItem = null;
int intSourceCount = 0;
if (m_dataSource is DataTable)
{
intSourceCount = (m_dataSource as DataTable).Rows.Count;
}
else if (typeof(IList).IsAssignableFrom(m_dataSource.GetType()))
{
intSourceCount = (m_dataSource as IList).Count;
}
foreach (Control item in this.panRow.Controls)
{
if (intIndex >= intSourceCount)
{
item.Visible = false;
}
else
{
var row = (item as IDataGridViewRow);
row.IsShowCheckBox = m_isShowCheckBox;
if (m_dataSource is DataTable)
{
row.DataSource = (m_dataSource as DataTable).Rows[intIndex];
}
else
{
row.DataSource = (m_dataSource as IList)[intIndex];
}
row.BindingCellData();
item.Height = m_rowHeight;
item.Visible = true;
item.BringToFront();
if (lastItem == null)
lastItem = item;
Rows.Add(row);
}
intIndex++;
}
if (intIndex < intSourceCount)
{
for (int i = intIndex; i < intSourceCount; i++)
{
IDataGridViewRow row = (IDataGridViewRow)Activator.CreateInstance(m_rowType);
if (m_dataSource is DataTable)
{
row.DataSource = (m_dataSource as DataTable).Rows[i];
}
else
{
row.DataSource = (m_dataSource as IList)[i];
}
row.Columns = m_columns;
List<Control> lstCells = new List<Control>();
row.IsShowCheckBox = m_isShowCheckBox;
row.ReloadCells();
row.BindingCellData();
Control rowControl = (row as Control);
rowControl.Height = m_rowHeight;
this.panRow.Controls.Add(rowControl);
rowControl.Dock = DockStyle.Top;
row.CellClick += (a, b) => { SetSelectRow(rowControl, b); };
row.CheckBoxChangeEvent += (a, b) => { SetSelectRow(rowControl, b); };
row.SourceChanged += RowSourceChanged;
rowControl.BringToFront();
Rows.Add(row);
if (lastItem == null)
lastItem = rowControl;
}
}
if (lastItem != null && intSourceCount == m_showCount)
{
lastItem.Height = this.panRow.Height - (m_showCount - 1) * m_rowHeight;
}
}
}
finally
{
ControlHelper.FreezeControl(this.panRow, false);
}
}
/// <summary>
/// 快捷键
/// </summary>
/// <param name="msg"></param>
/// <param name="keyData"></param>
/// <returns></returns>
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Up)
{
Previous();
}
else if (keyData == Keys.Down)
{
Next();
}
else if (keyData == Keys.Home)
{
First();
}
else if (keyData == Keys.End)
{
End();
}
return base.ProcessCmdKey(ref msg, keyData);
}
/// <summary>
/// 选中第一个
/// </summary>
public void First()
{
if (Rows == null || Rows.Count <= 0)
return;
Control c = null;
c = (Rows[0] as Control);
SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = 0 });
}
/// <summary>
/// 选中上一个
/// </summary>
public void Previous()
{
if (Rows == null || Rows.Count <= 0)
return;
Control c = null;
int index = Rows.IndexOf(m_selectRow);
if (index - 1 >= 0)
{
c = (Rows[index - 1] as Control);
SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = index - 1 });
}
}
/// <summary>
/// 选中下一个
/// </summary>
public void Next()
{
if (Rows == null || Rows.Count <= 0)
return;
Control c = null;
int index = Rows.IndexOf(m_selectRow);
if (index + 1 < Rows.Count)
{
c = (Rows[index + 1] as Control);
SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = index + 1 });
}
}
/// <summary>
/// 选中最后一个
/// </summary>
public void End()
{
if (Rows == null || Rows.Count <= 0)
return;
Control c = null;
c = (Rows[Rows.Count - 1] as Control);
SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = Rows.Count - 1 });
}
#endregion
#region 事件
void RowSourceChanged(object sender, DataGridViewEventArgs e)
{
if (SourceChanged != null)
SourceChanged(sender, e);
}
private void SetSelectRow(Control item, DataGridViewEventArgs e)
{
try
{
ControlHelper.FreezeControl(this, true);
if (item == null)
return;
if (item.Visible == false)
return;
this.FindForm().ActiveControl = this;
this.FindForm().ActiveControl = item;
if (m_selectRow != null)
{
if (m_selectRow == item)
return;
m_selectRow.SetSelect(false);
}
m_selectRow = item as IDataGridViewRow;
m_selectRow.SetSelect(true);
if (ItemClick != null)
{
ItemClick(item, e);
}
if (this.panRow.Controls.Count > 0)
{
if (item.Location.Y < 0)
{
this.panRow.AutoScrollPosition = new Point(0, Math.Abs(this.panRow.Controls[this.panRow.Controls.Count - 1].Location.Y) + item.Location.Y);
}
else if (item.Location.Y + m_rowHeight > this.panRow.Height)
{
this.panRow.AutoScrollPosition = new Point(0, Math.Abs(this.panRow.AutoScrollPosition.Y) + item.Location.Y - this.panRow.Height + m_rowHeight);
}
}
}
finally
{
ControlHelper.FreezeControl(this, false);
}
}
private void UCDataGridView_Resize(object sender, EventArgs e)
{
ResetShowCount();
ReloadSource();
}
#endregion
}
}
namespace HZH_Controls.Controls
{
partial class UCDataGridView
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region 组件设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.panHead = new System.Windows.Forms.Panel();
this.panColumns = new System.Windows.Forms.TableLayoutPanel();
this.ucSplitLine_H1 = new HZH_Controls.Controls.UCSplitLine_H();
this.panRow = new System.Windows.Forms.Panel();
this.panPage = new System.Windows.Forms.Panel();
this.panHead.SuspendLayout();
this.SuspendLayout();
//
// panHead
//
this.panHead.Controls.Add(this.panColumns);
this.panHead.Controls.Add(this.ucSplitLine_H1);
this.panHead.Dock = System.Windows.Forms.DockStyle.Top;
this.panHead.Location = new System.Drawing.Point(0, 0);
this.panHead.Name = "panHead";
this.panHead.Size = new System.Drawing.Size(1061, 40);
this.panHead.TabIndex = 0;
//
// panColumns
//
this.panColumns.ColumnCount = 1;
this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.panColumns.Dock = System.Windows.Forms.DockStyle.Fill;
this.panColumns.Location = new System.Drawing.Point(0, 0);
this.panColumns.Name = "panColumns";
this.panColumns.RowCount = 1;
this.panColumns.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.panColumns.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.panColumns.Size = new System.Drawing.Size(1061, 39);
this.panColumns.TabIndex = 1;
//
// ucSplitLine_H1
//
this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(232)))), ((int)(((byte)(232)))), ((int)(((byte)(232)))));
this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.ucSplitLine_H1.Location = new System.Drawing.Point(0, 39);
this.ucSplitLine_H1.Name = "ucSplitLine_H1";
this.ucSplitLine_H1.Size = new System.Drawing.Size(1061, 1);
this.ucSplitLine_H1.TabIndex = 0;
this.ucSplitLine_H1.TabStop = false;
//
// panRow
//
this.panRow.AutoScroll = true;
this.panRow.Dock = System.Windows.Forms.DockStyle.Fill;
this.panRow.Location = new System.Drawing.Point(0, 40);
this.panRow.Name = "panRow";
this.panRow.Size = new System.Drawing.Size(1061, 475);
this.panRow.TabIndex = 1;
//
// panPage
//
this.panPage.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panPage.Location = new System.Drawing.Point(0, 515);
this.panPage.Name = "panPage";
this.panPage.Size = new System.Drawing.Size(1061, 50);
this.panPage.TabIndex = 0;
this.panPage.Visible = false;
//
// UCDataGridView
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.Color.White;
this.Controls.Add(this.panRow);
this.Controls.Add(this.panPage);
this.Controls.Add(this.panHead);
this.Name = "UCDataGridView";
this.Size = new System.Drawing.Size(1061, 565);
this.Resize += new System.EventHandler(this.UCDataGridView_Resize);
this.panHead.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panHead;
private System.Windows.Forms.TableLayoutPanel panColumns;
private UCSplitLine_H ucSplitLine_H1;
private System.Windows.Forms.Panel panRow;
private System.Windows.Forms.Panel panPage;
}
}
如果你仔细看,你会发现行我用了类型进行传入,当你需要更丰富的行内容的时候,可以自定义行控件,然后通过RowType属性传入
分页控件我使用了分页控件基类UCPagerControlBase,这样做的好处就是你同样可以扩展分页控件
用处及效果
调用示例
1 List<DataGridViewColumnEntity> lstCulumns = new List<DataGridViewColumnEntity>();
2 lstCulumns.Add(new DataGridViewColumnEntity() { DataField = "ID", HeadText = "编号", Width = 70, WidthType = SizeType.Absolute });
3 lstCulumns.Add(new DataGridViewColumnEntity() { DataField = "Name", HeadText = "姓名", Width = 50, WidthType = SizeType.Percent });
4 lstCulumns.Add(new DataGridViewColumnEntity() { DataField = "Age", HeadText = "年龄", Width = 50, WidthType = SizeType.Percent });
5 lstCulumns.Add(new DataGridViewColumnEntity() { DataField = "Birthday", HeadText = "生日", Width = 50, WidthType = SizeType.Percent, Format = (a) => { return ((DateTime)a).ToString("yyyy-MM-dd"); } });
6 lstCulumns.Add(new DataGridViewColumnEntity() { DataField = "Sex", HeadText = "性别", Width = 50, WidthType = SizeType.Percent, Format = (a) => { return ((int)a) == 0 ? "女" : "男"; } });
7 this.ucDataGridView1.Columns = lstCulumns;
8 this.ucDataGridView1.IsShowCheckBox = true;
9 List<object> lstSource = new List<object>();
10 for (int i = 0; i < 200; i++)
11 {
12 TestModel model = new TestModel()
13 {
14 ID = i.ToString(),
15 Age = 3 * i,
16 Name = "姓名——" + i,
17 Birthday = DateTime.Now.AddYears(-10),
18 Sex = i % 2
19 };
20 lstSource.Add(model);
21 }
22
23 var page = new UCPagerControl2();
24 page.DataSource = lstSource;
25 this.ucDataGridView1.Page = page;
26 this.ucDataGridView1.First();
如果使用分页控件,则将数据源指定给分页控件,否则直接指定给表格控件数据源
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星 星吧