Winform系列——好看的DataGridView折叠控件-CSharp开发技术站 (2023)

来园子几年了,第一次写博客。以前看到别人的博客就在想:这些人怎么能有这么多时间整理这么多知识,难道他们不用工作、不用写代码、不用交付测试?随着工作阅历的增加,发现其实并不是时间的问题,关键一个字:懒。其实写博客的好处大家伙都心知肚明。呵呵,第一次写就这么多废话,看样子真是年纪大了。

其实自己之前的5年也一直是做BS的系统,现在刚换的一家公司需要做一个CS的产品。屌了,自己之前一点经验都没有呢,没办法,既来之则安之,学呗。于是乎各种百度、各种视频,各种资料。系统其中一个需求就是需要表格折叠显示,这如果在BS里面那太简单了,JqGrid默认都自带,可是DataGridview不支持折叠啊,咋办。自己封装呗,于是乎又是各种百度,这种源码学习。最后借鉴源码封了这么一个东西,发出来分享下,也能让自己加深印象。首先不多说,上图:

Winform系列——好看的DataGridView折叠控件-CSharp开发技术站 (1)

Winform系列——好看的DataGridView折叠控件-CSharp开发技术站 (2)

Winform系列——好看的DataGridView折叠控件-CSharp开发技术站 (3)

Winform系列——好看的DataGridView折叠控件-CSharp开发技术站 (4)

大概的效果就是这样。上代码。

1、首先重写DataGridview,代码如下:

Winform系列——好看的DataGridView折叠控件-CSharp开发技术站 (5)

 1 public class MasterControl : DataGridView 2  { 3 #region 字段 4 private List<int> rowCurrent = new List<int>(); 5 internal static int rowDefaultHeight = 22; 6 internal static int rowExpandedHeight = 300; 7 internal static int rowDefaultDivider = 0; 8 internal static int rowExpandedDivider = 300 - 22; 9 internal static int rowDividerMargin = 5; 10 internal static bool collapseRow; 11      //detailControl变量作为一个容器用来保存子表格 12 public detailControl childView = new detailControl() { Visible = false }; // VBConversions Note: Initial value cannot be assigned here since it is non-static. Assignment has been moved to the class constructors. 13 // 14 internal System.Windows.Forms.ImageList RowHeaderIconList; 15 private System.ComponentModel.Container components = null; 16 // 17  DataSet _cDataset; 18 string _foreignKey; 19 string _primaryKey; 20 string _filterFormat; 21 private controlType EControlType; 22 public int ExpandRowIndex = 0; 23  24  25 #endregion 26  27 #region 构造函数 28 /// <summary> 29 /// 通过传递过来的枚举判断是两级还是三级展开,表的对应关系通过Relations来读取 30 /// 所以调用此构造函数的时候必须要讲Relations设置正确,才能正确显示层级关系。 31 /// oDataSet.Relations.Add("1", oDataSet.Tables["T1"].Columns["Menu_ID"], oDataSet.Tables["T2"].Columns["Menu_ID"]); 32 /// oDataSet.Relations.Add("2", oDataSet.Tables["T2"].Columns["Menu_Name2"], oDataSet.Tables["T3"].Columns["Menu_Name2"]); 33 /// 这两次Add的顺序不能颠倒,必须先添加一、二级的表关联,再添加二、三级的表关联 34 /// </summary> 35 /// <param name="cDataset">数据源DataSet,里面还有各个表的对应关系</param> 36 /// <param name="eControlType">枚举类型</param> 37 public MasterControl(DataSet cDataset, controlType eControlType) 38  { 39  SetMasterControl(cDataset, eControlType);  40  } 41  42 /// <summary> 43 /// 第二种使用方法 44 /// </summary> 45 /// <param name="lstData1">折叠控件第一层的集合</param> 46 /// <param name="lstData2">折叠控件第二层的集合</param> 47 /// <param name="lstData3">折叠控件第三层的集合</param> 48 /// <param name="dicRelateKey1">第一二层之间对应主外键</param> 49 /// <param name="dicRelateKey2">第二三层之间对应主外键</param> 50 /// <param name="eControlType">枚举类型</param> 51 public MasterControl(object lstData1, object lstData2,  52 object lstData3, Dictionary<string, string> dicRelateKey1,  53 Dictionary<string ,string>dicRelateKey2, controlType eControlType) 54  { 55 var oDataSet = new DataSet(); 56 try 57  { 58 var oTable1 = new DataTable(); 59 oTable1 = Fill(lstData1); 60 oTable1.TableName = "T1"; 61  62 var oTable2 = Fill(lstData2); 63 oTable2.TableName = "T2"; 64  65 if (lstData3 == null || dicRelateKey2 == null || dicRelateKey2.Keys.Count <= 0) 66  { 67 oDataSet.Tables.AddRange(new DataTable[] { oTable1, oTable2 }); 68 oDataSet.Relations.Add("1", oDataSet.Tables["T1"].Columns[dicRelateKey1.Keys.FirstOrDefault()], oDataSet.Tables["T2"].Columns[dicRelateKey1.Values.FirstOrDefault()]); 69  } 70 else 71  { 72 var oTable3 = Fill(lstData3); 73 oTable3.TableName = "T3"; 74  75 oDataSet.Tables.AddRange(new DataTable[] { oTable1, oTable2, oTable3 }); 76 //这是对应关系的时候主键必须唯一 77 oDataSet.Relations.Add("1", oDataSet.Tables["T1"].Columns[dicRelateKey1.Keys.FirstOrDefault()], oDataSet.Tables["T2"].Columns[dicRelateKey1.Values.FirstOrDefault()]); 78 oDataSet.Relations.Add("2", oDataSet.Tables["T2"].Columns[dicRelateKey2.Keys.FirstOrDefault()], oDataSet.Tables["T3"].Columns[dicRelateKey2.Values.FirstOrDefault()]); 79  } 80  } 81 catch 82  { 83 oDataSet = new DataSet(); 84  } 85  SetMasterControl(oDataSet, eControlType); 86  } 87  88 /// <summary> 89 /// 控件初始化 90 /// </summary> 91 private void InitializeComponent() 92  { 93 this.components = new System.ComponentModel.Container(); 94 base.RowHeaderMouseClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(MasterControl_RowHeaderMouseClick); 95 base.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(MasterControl_RowPostPaint); 96 base.Scroll += new System.Windows.Forms.ScrollEventHandler(MasterControl_Scroll); 97 base.SelectionChanged += new System.EventHandler(MasterControl_SelectionChanged); 98 System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MasterControl)); 99 this.RowHeaderIconList = new System.Windows.Forms.ImageList(this.components);100 ((System.ComponentModel.ISupportInitialize)this).BeginInit();101 this.SuspendLayout();102 //103 //RowHeaderIconList104 //105 this.RowHeaderIconList.ImageStream = (System.Windows.Forms.ImageListStreamer)(resources.GetObject("RowHeaderIconList.ImageStream"));106 this.RowHeaderIconList.TransparentColor = System.Drawing.Color.Transparent;107 this.RowHeaderIconList.Images.SetKeyName(0, "expand.png");108 this.RowHeaderIconList.Images.SetKeyName(1, "collapse.png");109 //110 //MasterControl111 //112 ((System.ComponentModel.ISupportInitialize)this).EndInit();113 this.ResumeLayout(false);114 115  }116 #endregion117 118 #region 数据绑定119 /// <summary>120 /// 设置表之间的主外键关联121 /// </summary>122 /// <param name="tableName">DataTable的表名称</param>123 /// <param name="foreignKey">外键</param>124 public void setParentSource(string tableName, string primarykey, string foreignKey)125  {126 this.DataSource = new DataView(_cDataset.Tables[tableName]);127 cModule.setGridRowHeader(this);128 _foreignKey = foreignKey;129 _primaryKey = primarykey;130 if (_cDataset.Tables[tableName].Columns[primarykey].GetType().ToString() == typeof(int).ToString()131 || _cDataset.Tables[tableName].Columns[primarykey].GetType().ToString() == typeof(double).ToString()132 || _cDataset.Tables[tableName].Columns[primarykey].GetType().ToString() == typeof(decimal).ToString())133  {134 _filterFormat = foreignKey + "={0}";135  }136 else137  {138 _filterFormat = foreignKey + "=\'{0}\'";139  }140  }141 #endregion142 143 #region 事件144 //控件的行头点击事件145 private void MasterControl_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)146  {147 try148  {149 Rectangle rect = new Rectangle(System.Convert.ToInt32((double)(rowDefaultHeight - 16) / 2), System.Convert.ToInt32((double)(rowDefaultHeight - 16) / 2), 16, 16);150 if (rect.Contains(e.Location))151  {152 //缩起153 if (rowCurrent.Contains(e.RowIndex))154  {155  rowCurrent.Clear();156 this.Rows[e.RowIndex].Height = rowDefaultHeight;157 this.Rows[e.RowIndex].DividerHeight = rowDefaultDivider;158 159 this.ClearSelection();160 collapseRow = true;161 this.Rows[e.RowIndex].Selected = true;162 if (EControlType == controlType.middle)163  {164 var oParent = ((MasterControl)this.Parent.Parent);165 oParent.Rows[oParent.ExpandRowIndex].Height = rowDefaultHeight * (this.Rows.Count + 4);166 oParent.Rows[oParent.ExpandRowIndex].DividerHeight = rowDefaultHeight * (this.Rows.Count + 3);167 if (oParent.Rows[oParent.ExpandRowIndex].Height > 500)168  {169 oParent.Rows[oParent.ExpandRowIndex].Height = 500;170 oParent.Rows[oParent.ExpandRowIndex].Height = 480;171  }172  }173  }174 //展开175 else176  {177 if (!(rowCurrent.Count == 0))178  {179 var eRow = rowCurrent[0];180  rowCurrent.Clear();181 this.Rows[eRow].Height = rowDefaultHeight;182 this.Rows[eRow].DividerHeight = rowDefaultDivider;183 this.ClearSelection();184 collapseRow = true;185 this.Rows[eRow].Selected = true;186  }187  rowCurrent.Add(e.RowIndex);188 this.ClearSelection();189 collapseRow = true;190 this.Rows[e.RowIndex].Selected = true;191 this.ExpandRowIndex = e.RowIndex;192 193 this.Rows[e.RowIndex].Height = 66 + rowDefaultHeight * (((DataView)(childView.childGrid[0].DataSource)).Count + 1);194 this.Rows[e.RowIndex].DividerHeight = 66 + rowDefaultHeight * (((DataView)(childView.childGrid[0].DataSource)).Count);195 //设置一个最大高度196 if (this.Rows[e.RowIndex].Height > 500)197  {198 this.Rows[e.RowIndex].Height = 500;199 this.Rows[e.RowIndex].DividerHeight = 480;200  }201 if (EControlType == controlType.middle)202  {203 if (this.Parent.Parent.GetType() != typeof(MasterControl))204 return;205 var oParent = ((MasterControl)this.Parent.Parent);206 oParent.Rows[oParent.ExpandRowIndex].Height = this.Rows[e.RowIndex].Height + rowDefaultHeight * (this.Rows.Count + 3);207 oParent.Rows[oParent.ExpandRowIndex].DividerHeight = this.Rows[e.RowIndex].DividerHeight + rowDefaultHeight * (this.Rows.Count + 3);208 if (oParent.Rows[oParent.ExpandRowIndex].Height > 500)209  {210 oParent.Rows[oParent.ExpandRowIndex].Height = 500;211 oParent.Rows[oParent.ExpandRowIndex].Height = 480;212  }213  }214 //if (EControlType == controlType.outside)215 //{216 // //SetControl(this);217 //}218 //this.Rows[e.RowIndex].Height = rowExpandedHeight;219 //this.Rows[e.RowIndex].DividerHeight = rowExpandedDivider;220  }221 //this.ClearSelection();222 //collapseRow = true;223 //this.Rows[e.RowIndex].Selected = true;224  }225 else226  {227 collapseRow = false;228  }229  }230 catch (Exception ex)231  {232 233  }234  }235 236 //控件的行重绘事件237 private void MasterControl_RowPostPaint(object obj_sender, DataGridViewRowPostPaintEventArgs e)238  {239 try240  {241 var sender = (DataGridView)obj_sender;242 //set childview control243 var rect = new Rectangle((int)(e.RowBounds.X + ((double)(rowDefaultHeight - 16) / 2)), (int)(e.RowBounds.Y + ((double)(rowDefaultHeight - 16) / 2)), 16, 16);244 if (collapseRow)245  {246 if (this.rowCurrent.Contains(e.RowIndex))247  {248 #region 更改点开后背景色 刘金龙249 var rect1 = new Rectangle(e.RowBounds.X, e.RowBounds.Y + rowDefaultHeight, e.RowBounds.Width, e.RowBounds.Height - rowDefaultHeight);250 using (Brush b = new SolidBrush(Color.FromArgb(164, 169, 143)))251  {252  e.Graphics.FillRectangle(b, rect1);253  } 254 #endregion255 sender.Rows[e.RowIndex].DividerHeight = sender.Rows[e.RowIndex].Height - rowDefaultHeight;256 e.Graphics.DrawImage(RowHeaderIconList.Images[(int)rowHeaderIcons.collapse], rect);257 childView.Location = new Point(e.RowBounds.Left + sender.RowHeadersWidth, e.RowBounds.Top + rowDefaultHeight + 5);258 childView.Width = e.RowBounds.Right - sender.RowHeadersWidth;259 childView.Height = System.Convert.ToInt32(sender.Rows[e.RowIndex].DividerHeight - 10);260 childView.Visible = true;261  }262 else263  {264 childView.Visible = false;265 e.Graphics.DrawImage(RowHeaderIconList.Images[(int)rowHeaderIcons.expand], rect);266  }267 collapseRow = false;268  }269 else270  {271 if (this.rowCurrent.Contains(e.RowIndex))272  {273 #region 更改点开后背景色 刘金龙274 var rect1 = new Rectangle(e.RowBounds.X, e.RowBounds.Y + rowDefaultHeight, e.RowBounds.Width, e.RowBounds.Height - rowDefaultHeight);275 using (Brush b = new SolidBrush(Color.FromArgb(164,169,143)))276  {277  e.Graphics.FillRectangle(b, rect1);278  } 279 #endregion280 sender.Rows[e.RowIndex].DividerHeight = sender.Rows[e.RowIndex].Height - rowDefaultHeight;281 e.Graphics.DrawImage(RowHeaderIconList.Images[(int)rowHeaderIcons.collapse], rect);282 childView.Location = new Point(e.RowBounds.Left + sender.RowHeadersWidth, e.RowBounds.Top + rowDefaultHeight + 5);283 childView.Width = e.RowBounds.Right - sender.RowHeadersWidth;284 childView.Height = System.Convert.ToInt32(sender.Rows[e.RowIndex].DividerHeight - 10);285 childView.Visible = true;286  }287 else288  {289 childView.Visible = false;290 e.Graphics.DrawImage(RowHeaderIconList.Images[(int)rowHeaderIcons.expand], rect);291  }292  }293  cModule.rowPostPaint_HeaderCount(sender, e);294  }295 catch296  {297 298  }299  }300 301 //控件的滚动条滚动事件302 private void MasterControl_Scroll(object sender, ScrollEventArgs e)303  {304 try305  {306 if (!(rowCurrent.Count == 0))307  {308 collapseRow = true;309 this.ClearSelection();310 this.Rows[rowCurrent[0]].Selected = true;311  }312  }313 catch314  {315 316  }317  }318 319 //控件的单元格选择事件320 private void MasterControl_SelectionChanged(object sender, EventArgs e)321  {322 try323  {324 if (!(this.RowCount == 0))325  {326 if (rowCurrent.Contains(this.CurrentRow.Index))327  {328 foreach (DataGridView cGrid in childView.childGrid)329  {330 ((DataView)cGrid.DataSource).RowFilter = string.Format(_filterFormat, this[_primaryKey, this.CurrentRow.Index].Value);331  }332  }333  }334  }335 catch336  {337 338  }339  }340 #endregion341 342 #region Private343 //设置构造函数的参数344 private void SetMasterControl(DataSet cDataset, controlType eControlType)345  {346 //1.控件初始化赋值347 this.Controls.Add(childView);348  InitializeComponent();349 _cDataset = cDataset;350 childView._cDataset = cDataset;351 cModule.applyGridTheme(this);352 Dock = DockStyle.Fill;353 EControlType = eControlType;354 this.AllowUserToAddRows = false;355 356 //2.通过读取DataSet里面的Relations得到表的关联关系357 if (cDataset.Relations.Count <= 0)358  {359 return;360  }361  DataRelation oRelates;362 if (eControlType == controlType.outside)363  {364 oRelates = cDataset.Relations[1];365 childView.Add(oRelates.ParentTable.TableName, oRelates.ParentColumns[0].ColumnName, oRelates.ChildColumns[0].ColumnName);366  }367 else if (eControlType == controlType.middle)368  {369 oRelates = cDataset.Relations[cDataset.Relations.Count - 1];370  childView.Add2(oRelates.ChildTable.TableName);371  }372 373 //3.设置主外键对应关系374 oRelates = cDataset.Relations[0];375 //主表里面的值,副表里面的过滤字段376 setParentSource(oRelates.ParentTable.TableName,oRelates.ParentColumns[0].ColumnName, oRelates.ChildColumns[0].ColumnName);377  }378 379 private void SetControl(MasterControl oGrid)380  {381  oGrid.childView.RemoveControl();382 //oGrid.childView.Controls.RemoveByKey("ChildrenMaster");383 //384 //var oRelates = _cDataset.Relations[1];385 //oGrid.childView.Add(oRelates.ParentTable.TableName, oRelates.ChildColumns[0].ColumnName);386 387 388 //foreach (var oGridControl in oGrid.Controls)389 //{390 // if (oGridControl.GetType() != typeof(detailControl))391 // {392 // continue;393 // }394 // var DetailControl =(detailControl)oGridControl;395 // foreach (var odetailControl in DetailControl.Controls)396 // {397 // if (odetailControl.GetType() != typeof(MasterControl))398 // {399 // continue;400 // }401 // var OMasterControl = (MasterControl)odetailControl;402 // foreach (var oMasterControl in OMasterControl.Controls)403 // {404 // if (oMasterControl.GetType() == typeof(detailControl))405 // {406 // ((detailControl)oMasterControl).Visible = false;407 // return;408 // }409 // }410 // }411 //}412  }413 414 //将List集合转换成DataTable415 private DataTable Fill(object obj)416  {417 if(!(obj is IList))418  {419 return null;420  }421 var objlist = obj as IList;422 if (objlist == null || objlist.Count <= 0)423  {424 return null;425  }426 var tType = objlist[0];427 DataTable dt = new DataTable(tType.GetType().Name);428  DataColumn column;429  DataRow row;430 System.Reflection.PropertyInfo[] myPropertyInfo = tType.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);431 foreach (var t in objlist)432  {433 if (t == null)434  {435 continue;436  }437 row = dt.NewRow();438 for (int i = 0, j = myPropertyInfo.Length; i < j; i++)439  {440 System.Reflection.PropertyInfo pi = myPropertyInfo[i];441 string name = pi.Name;442 if (dt.Columns[name] == null)443  {444 column = new DataColumn(name, pi.PropertyType);445  dt.Columns.Add(column);446  }447 row[name] = pi.GetValue(t, null);448  }449  dt.Rows.Add(row);450  }451 return dt;452  }453 #endregion454 }

View Code

2、detailControl变量作为一个容器用来保存子表格,代码如下:

Winform系列——好看的DataGridView折叠控件-CSharp开发技术站 (6)

 1 public class detailControl : Ewin.Client.Frame.Controls.EwinPanel 2  { 3 #region 字段 4 public List<DataGridView> childGrid = new List<DataGridView>(); 5 public DataSet _cDataset; 6 #endregion 7  8 #region 方法 9 public void Add(string tableName, string strPrimaryKey, string strForeignKey)10  {11 //TabPage tPage = new TabPage() { Text = pageCaption };12 //this.Controls.Add(tPage);13 var newGrid = new MasterControl(_cDataset, controlType.middle) { Dock = DockStyle.Fill, DataSource = new DataView(_cDataset.Tables[tableName]) };14 newGrid.setParentSource(tableName, strPrimaryKey, strForeignKey);//设置主外键15 //newGrid.Name = "ChildrenMaster";16 //tPage.Controls.Add(newGrid);17 this.Controls.Add(newGrid);18 //this.BorderStyle = BorderStyle.FixedSingle;19  cModule.applyGridTheme(newGrid);20  cModule.setGridRowHeader(newGrid);21 newGrid.RowPostPaint += cModule.rowPostPaint_HeaderCount;22  childGrid.Add(newGrid);23  }24 25 public void Add2(string tableName)26  {27 //TabPage tPage = new TabPage() { Text = pageCaption };28 //this.Controls.Add(tPage);29 DataGridView newGrid = new Ewin.Client.Frame.Controls.EwinGrid() { Dock = DockStyle.Fill, DataSource = new DataView(_cDataset.Tables[tableName]) };30 newGrid.AllowUserToAddRows = false;31 //tPage.Controls.Add(newGrid);32 this.Controls.Add(newGrid);33  cModule.applyGridTheme(newGrid);34  cModule.setGridRowHeader(newGrid);35 newGrid.RowPostPaint += cModule.rowPostPaint_HeaderCount;36  childGrid.Add(newGrid);37  }38 39 public void RemoveControl()40  {41 this.Controls.Remove(childGrid[0]);42  childGrid.Clear();43  }44 #endregion45 46 }

View Code

3、cModule.cs用来设置样式

Winform系列——好看的DataGridView折叠控件-CSharp开发技术站 (7)

 1 namespace Ewin.Client.Frame.UcGrid 2 { 3 /// <summary> 4 /// 折叠控件样式以及行数操作类 5 /// </summary> 6 sealed class cModule 7  { 8 #region CustomGrid 9 static System.Windows.Forms.DataGridViewCellStyle dateCellStyle = new System.Windows.Forms.DataGridViewCellStyle { Alignment = DataGridViewContentAlignment.MiddleRight }; 10 static System.Windows.Forms.DataGridViewCellStyle amountCellStyle = new System.Windows.Forms.DataGridViewCellStyle { Alignment = DataGridViewContentAlignment.MiddleRight, Format = "N2" }; 11 static System.Windows.Forms.DataGridViewCellStyle gridCellStyle = new System.Windows.Forms.DataGridViewCellStyle 12  { 13 Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft, 14 BackColor = System.Drawing.Color.FromArgb(System.Convert.ToInt32(System.Convert.ToByte(79)), System.Convert.ToInt32(System.Convert.ToByte(129)), System.Convert.ToInt32(System.Convert.ToByte(189))), 15 Font = new System.Drawing.Font("Segoe UI", (float)(10.0F), System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, System.Convert.ToByte(0)), 16 ForeColor = System.Drawing.SystemColors.ControlLightLight, 17 SelectionBackColor = System.Drawing.SystemColors.Highlight, 18 SelectionForeColor = System.Drawing.SystemColors.HighlightText, 19 WrapMode = System.Windows.Forms.DataGridViewTriState.True 20  }; 21 static System.Windows.Forms.DataGridViewCellStyle gridCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle 22  { 23 Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft, 24 BackColor = System.Drawing.SystemColors.ControlLightLight, 25 Font = new System.Drawing.Font("Segoe UI", (float)(10.0F), System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, System.Convert.ToByte(0)), 26 ForeColor = System.Drawing.SystemColors.ControlText, 27 SelectionBackColor = System.Drawing.Color.FromArgb(System.Convert.ToInt32(System.Convert.ToByte(155)), System.Convert.ToInt32(System.Convert.ToByte(187)), System.Convert.ToInt32(System.Convert.ToByte(89))), 28 SelectionForeColor = System.Drawing.SystemColors.HighlightText, 29 WrapMode = System.Windows.Forms.DataGridViewTriState.False 30  }; 31 static System.Windows.Forms.DataGridViewCellStyle gridCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle 32  { 33 Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft, 34 BackColor = System.Drawing.Color.WhiteSmoke, 35 Font = new System.Drawing.Font("Segoe UI", (float)(10.0F), System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, System.Convert.ToByte(0)), 36 ForeColor = System.Drawing.SystemColors.WindowText, 37 SelectionBackColor = System.Drawing.Color.FromArgb(System.Convert.ToInt32(System.Convert.ToByte(155)), System.Convert.ToInt32(System.Convert.ToByte(187)), System.Convert.ToInt32(System.Convert.ToByte(89))), 38 SelectionForeColor = System.Drawing.SystemColors.HighlightText, 39 WrapMode = System.Windows.Forms.DataGridViewTriState.True 40  }; 41  42 //设置表格的主题样式 43 static public void applyGridTheme(DataGridView grid) 44  { 45 grid.AllowUserToAddRows = false; 46 grid.AllowUserToDeleteRows = false; 47 grid.BackgroundColor = System.Drawing.SystemColors.Window; 48 grid.BorderStyle = System.Windows.Forms.BorderStyle.None; 49 grid.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; 50 grid.ColumnHeadersDefaultCellStyle = gridCellStyle; 51 grid.ColumnHeadersHeight = 32; 52 grid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; 53 grid.DefaultCellStyle = gridCellStyle2; 54 grid.EnableHeadersVisualStyles = false; 55 grid.GridColor = System.Drawing.SystemColors.GradientInactiveCaption; 56 //grid.ReadOnly = true; 57 grid.RowHeadersVisible = true; 58 grid.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; 59 grid.RowHeadersDefaultCellStyle = gridCellStyle3; 60 grid.Font = gridCellStyle.Font; 61  } 62  63 //设置表格单元格样式 64 static public void setGridRowHeader(DataGridView dgv, bool hSize = false) 65  { 66 dgv.TopLeftHeaderCell.Value = "NO "; 67 dgv.TopLeftHeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; 68  dgv.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders); 69 foreach (DataGridViewColumn cCol in dgv.Columns) 70  { 71 if (cCol.ValueType.ToString() == typeof(DateTime).ToString()) 72  { 73 cCol.DefaultCellStyle = dateCellStyle; 74  } 75 else if (cCol.ValueType.ToString() == typeof(decimal).ToString() || cCol.ValueType.ToString() == typeof(double).ToString()) 76  { 77 cCol.DefaultCellStyle = amountCellStyle; 78  } 79  } 80 if (hSize) 81  { 82 dgv.RowHeadersWidth = dgv.RowHeadersWidth + 16; 83  } 84  dgv.AutoResizeColumns(); 85  } 86  87 //设置表格的行号 88 static public void rowPostPaint_HeaderCount(object obj_sender, DataGridViewRowPostPaintEventArgs e) 89  { 90 try 91  { 92 var sender = (DataGridView)obj_sender; 93 //set rowheader count 94 DataGridView grid = (DataGridView)sender; 95 string rowIdx = System.Convert.ToString((e.RowIndex + 1).ToString()); 96 var centerFormat = new StringFormat(); 97 centerFormat.Alignment = StringAlignment.Center; 98 centerFormat.LineAlignment = StringAlignment.Center; 99 Rectangle headerBounds = new Rectangle(e.RowBounds.Left, e.RowBounds.Top,100 grid.RowHeadersWidth, e.RowBounds.Height - sender.Rows[e.RowIndex].DividerHeight);101  e.Graphics.DrawString(rowIdx, grid.Font, SystemBrushes.ControlText,102  headerBounds, centerFormat);103  }104 catch (Exception ex)105  {106 107  }108  }109 #endregion110  }111 112 /// <summary>113 /// 控件类型,是最外层的表格还是中间层的表格114 /// </summary>115 public enum controlType116  {117 outside = 0,118 middle = 1119  }120 121 /// <summary>122 /// 展开图标123 /// </summary>124 public enum rowHeaderIcons125  {126 expand = 0,127 collapse = 1128  }129 }

View Code

4、From页面调用

#region 使用方法一 //var oDataSet = GetDataSet(); // //masterDetail = new MasterControl(oDataSet, controlType.outside); #endregion #region 使用方法二 var dicRelateData1 = new Dictionary<string, string>(); var dicRelateData2 = new Dictionary<string, string>(); dicRelateData1.Add("Menu_ID","Menu_ID");//表格一和表格二之间的主外键关系 dicRelateData2.Add("Menu_Name2","Menu_Name2");//表格二和表格三之间的主外键关系
masterDetail = new MasterControl(GetDataSource(), GetDataSource2(), GetDataSource3(), dicRelateData1, dicRelateData2, controlType.outside); #endregion panelView.Controls.Add(masterDetail);

昨天应领导要求,折叠控件增加了折叠线的效果,看起来有没有更加像模像样了。~~~

其实就在行重绘事件private void MasterControl_RowPostPaint(object obj_sender, DataGridViewRowPostPaintEventArgs e)里面增加了如下代码:

using (Pen p = new Pen(Color.GhostWhite))
{
var iHalfWidth = (e.RowBounds.Left + sender.RowHeadersWidth) / 2;
var oPointHLineStart = new Point(rect1.X + iHalfWidth, rect1.Y);
var oPointHLineEnd = new Point(rect1.X + iHalfWidth, rect1.Y + rect1.Height / 2);
e.Graphics.DrawLine(p, oPointHLineStart, oPointHLineEnd);
//折叠线
e.Graphics.DrawLine(p, oPointHLineEnd, new Point(oPointHLineEnd.X + iHalfWidth, oPointHLineEnd.Y));
}

效果如下:

Winform系列——好看的DataGridView折叠控件-CSharp开发技术站 (8)

2015-07-01

PS:原以为CS的控件大家不会太感兴趣,这两天很多园友找我要源码,其实并非舍不得将源码共享,只是很多东西融入到项目中了很难分离出来,需要时间整理,望理解。知道这么多园友对CS的控件也感兴趣,我就抽时间整理了下折叠控件的Demo。本着大家共同进步的原则将源码共享出来。好的东西就要共享,咱.Net也要慢慢走共享开源路线哈~~

源码下载

Top Articles
Latest Posts
Article information

Author: Rueben Jacobs

Last Updated: 02/19/2023

Views: 6228

Rating: 4.7 / 5 (77 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Rueben Jacobs

Birthday: 1999-03-14

Address: 951 Caterina Walk, Schambergerside, CA 67667-0896

Phone: +6881806848632

Job: Internal Education Planner

Hobby: Candle making, Cabaret, Poi, Gambling, Rock climbing, Wood carving, Computer programming

Introduction: My name is Rueben Jacobs, I am a cooperative, beautiful, kind, comfortable, glamorous, open, magnificent person who loves writing and wants to share my knowledge and understanding with you.