using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace TemuKJD.Extension { public static class DataGridViewExtension { public static object GetCellValueFromColumnName(this DataGridViewCellCollection CellCollection, string name) { return CellCollection.Cast().FirstOrDefault(c => c.OwningColumn.Name == name)?.Value; } public static CheckBox AddSelectorColumn(this DataGridView dgv, string columnName = "Selected", Action addHeaderCheckBoxOverride = null) { if (dgv.Columns[columnName] == null) { //var dt = dgv.Table(); //var dcol = new DataColumn(columnName, typeof(bool)); //dt.Columns.Add(dcol); //dt.ColumnChanged += (s, e) => //{ // var chCols = e.Row.GetChangedColumns(); // if (chCols.Count == 1 && chCols[0].Equals(dcol)) // e.Row.AcceptChanges(); //}; } var col = dgv.Columns[columnName]; col.HeaderText = ""; col.ReadOnly = false; if (addHeaderCheckBoxOverride != null) { addHeaderCheckBoxOverride(col); return null; } else { return col.AddHeaderCheckBox(); } } public static CheckBox AddHeaderCheckBox(this DataGridViewColumn column, HorizontalAlignment align = HorizontalAlignment.Center, int leftBorderOffset = 0, int rightBorderOffset = 0, Func getValue = null, Action setValue = null, bool isSetCheckedChangedEvent = true, CheckBox checkBox = null, bool isClearHeaderText = false) { if (column?.DataGridView == null) //throw new ArgumentNullException("First you need to add the column to grid."); MessageBox.Show("DataGridView中没有对应的CheckBox列"); // Creating checkbox without panel if (checkBox == null) { checkBox = new CheckBox(); checkBox.Name = "chk" + column.Name; } checkBox.Size = new Size(15, 15); checkBox.BackColor = Color.Transparent; checkBox.Enabled = true; // Reset properties checkBox.Padding = new Padding(0); checkBox.Margin = new Padding(0); checkBox.Text = ""; if (isClearHeaderText) column.HeaderText = ""; var changedByUser = true; var dgv = column.DataGridView; if (isSetCheckedChangedEvent) { checkBox.CheckedChanged += (s, e) => { if (changedByUser) { try { changedByUser = false; if (dgv.IsCurrentCellInEditMode && dgv.CurrentCell.OwningColumn.Name.Equals(column.Name)) dgv.EndEdit(); var dgvRows = new List((dgv.SelectedRows.Count < 2 ? (ICollection)dgv.Rows : dgv.SelectedRows).Cast()); dgvRows = dgvRows.Where(r => r.Visible == true).ToList(); if (column.IsDataBound) { //adding to list because of BindingSource sort by that column var boundItems = new List(); var areDataRows = dgvRows.Count < 1 || dgvRows[0].DataBoundItem is DataRowView; if (areDataRows) { foreach (DataGridViewRow row in dgvRows) boundItems.Add(((DataRowView)row.DataBoundItem).Row); foreach (DataRow dr in boundItems) { var val = dr[column.DataPropertyName]; if ((val is bool && (bool)val) != checkBox.Checked) dr[column.DataPropertyName] = checkBox.Checked; } } else { foreach (DataGridViewRow row in dgvRows) boundItems.Add(row.DataBoundItem); foreach (var item in boundItems) { var val = getValue(item); if (val != checkBox.Checked) setValue(item, checkBox.Checked); } } } else { foreach (DataGridViewRow dgr in dgvRows) { var cell = dgr.Cells[column.Name]; if ((cell.Value is bool && (bool)cell.Value) != checkBox.Checked) cell.Value = checkBox.Checked; } } } finally { changedByUser = true; } } }; } // Add checkbox to datagrid cell dgv.Controls.Add(checkBox); Action onColResize = () => { var colCheck = dgv.Columns[column.Name]; if (colCheck == null) return; int colLeft = (dgv.RowHeadersVisible ? dgv.RowHeadersWidth : 0) - (colCheck.Frozen ? 0 : dgv.HorizontalScrollingOffset); foreach (DataGridViewColumn col in dgv.Columns) { if (col.DisplayIndex >= colCheck.DisplayIndex) break; if (!col.Visible) continue; colLeft += col.Width; } var newPoint = new Point(colLeft, dgv.ColumnHeadersHeight / 2 - checkBox.Height / 2); if (align == HorizontalAlignment.Left) newPoint.X += 3; else if (align == HorizontalAlignment.Center) newPoint.X += colCheck.Width / 2 - checkBox.Width / 2; else if (align == HorizontalAlignment.Right) newPoint.X += colCheck.Width - checkBox.Width - 3; var minLeft = colLeft + leftBorderOffset; var maxLeft = colLeft + colCheck.Width - checkBox.Width + rightBorderOffset; if (newPoint.X < minLeft) newPoint.X = minLeft; if (newPoint.X > maxLeft) newPoint.X = maxLeft; checkBox.Location = newPoint; checkBox.Visible = colCheck.Visible; }; dgv.ColumnWidthChanged += (s, e) => onColResize(); dgv.ColumnHeadersHeightChanged += (s, e) => onColResize(); dgv.Scroll += (s, e) => onColResize(); dgv.Resize += (s, e) => onColResize(); dgv.Sorted += (s, e) => onColResize(); dgv.RowHeadersWidthChanged += (s, e) => onColResize(); dgv.ColumnStateChanged += (s, e) => onColResize(); Action onDataChanged = (e) => { if (!changedByUser) return; if (e is DataColumnChangeEventArgs) { if (!((DataColumnChangeEventArgs)e).Column.ColumnName.Equals(column.Name)) return; } else if (e is ListChangedEventArgs) { var prop = ((ListChangedEventArgs)e).PropertyDescriptor; if (prop != null && !prop.Name.Equals(column.DataPropertyName)) return; } bool allAreTrue = true; foreach (DataGridViewRow row in dgv.SelectedRows.Count < 2 ? (ICollection)dgv.Rows : dgv.SelectedRows) { var val = row.Cells[column.Name].Value; if (!(val is bool) || !(bool)val) { allAreTrue = false; break; } } try { changedByUser = false; var tag = checkBox.Tag; checkBox.Tag = "AUTO"; try { if (isSetCheckedChangedEvent) { checkBox.Checked = allAreTrue; } } finally { checkBox.Tag = tag; } } finally { changedByUser = true; } }; dgv.CellClick += (s, e) => onDataChanged(e); dgv.CellContentClick += (s, e) => onDataChanged(e); dgv.SelectionChanged += (s, e) => onDataChanged(e); if (dgv.DataSource is BindingSource) ((BindingSource)dgv.DataSource).ListChanged += (s, e) => onDataChanged(e); else if (dgv.DataSource is DataSet) ((DataSet)dgv.DataSource).Tables[dgv.DataMember].ColumnChanged += (s, e) => onDataChanged(e); else if (dgv.DataSource is DataTable) ((DataTable)dgv.DataSource).ColumnChanged += (s, e) => onDataChanged(e); onColResize(); return checkBox; } /// /// 绘制合并的表头单元格 /// /// /// 单元格名称 /// 合并后的表头显示文字 /// 是否允许调整大小 public static void AddMergeColumnHeader(this DataGridView dgv, List colNameCollection, string headerText, bool isMultiLevelHeader = false) { int nHeight = 0; int nLeft = 0; int nTop = 0; int nWidth = 0; bool isMultiLevel = isMultiLevelHeader; // 是否为二级复合表头 bool isResize = false; // 是否已调整过表头 //合并列中某一列的列宽变化时,强制重绘表头 dgv.ColumnWidthChanged += (s, e) => { if (colNameCollection.Contains(e.Column.Name)) { foreach(var columnName in colNameCollection) { if (dgv.Columns.Contains(columnName)) dgv.InvalidateCell(dgv.Columns[columnName].HeaderCell); // 标记单元格为需要重绘 } dgv.Update(); } }; dgv.Scroll += (s, e) => { if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll) { bool tag = false; foreach (var columnName in colNameCollection) { var bounds = dgv.Columns[columnName].HeaderCell.ContentBounds; if (bounds.Left < 10 || bounds.Right > dgv.Width - 10) { tag = true; break; } } if (tag == true) { foreach (var columnName in colNameCollection) { if (dgv.Columns.Contains(columnName)) dgv.InvalidateCell(dgv.Columns[columnName].HeaderCell); // 标记单元格为需要重绘 } dgv.Update(); } } }; //处理重绘事件,绘制合并表头和二级表头 dgv.CellPainting += (s, e) => { if (e.RowIndex == -1 && e.ColumnIndex >=0) // 重绘表头单元格及标题 { string name = dgv.Columns[e.ColumnIndex].Name; // 调整为复合表头 if (isMultiLevel && !isResize) { dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing; dgv.ColumnHeadersHeight = e.CellBounds.Height * 2; isResize = true; } if (colNameCollection.Contains(name)) { e.PaintBackground(e.CellBounds, false); // false不绘制单元格背景 //e.PaintContent(e.CellBounds); // 绘制单元格内容,此处不要绘制 Brush brush; Pen pen; if (colNameCollection.IndexOf(name) == 0) { nTop = e.CellBounds.Top; nLeft = e.CellBounds.Left; nWidth = e.CellBounds.Width; if (isMultiLevelHeader) nHeight = e.CellBounds.Height / 2; else nHeight = e.CellBounds.Height; foreach (string str2 in colNameCollection) { if (!str2.Equals(name)) { nWidth += dgv.Columns[str2].Width; } } } //填充表头背景(覆盖原来的分隔线) Rectangle rtTmp = new Rectangle(nLeft, nTop, nWidth, nHeight); using (brush = new SolidBrush(/*e.CellStyle.BackColor*/dgv.BackgroundColor)) { var rtBounds = e.CellBounds; rtBounds.Height -= 1; e.Graphics.FillRectangle(brush, rtBounds); } //非多级表头,只需绘制最后一个连续表头的垂直分隔线 if (!isMultiLevelHeader) { if (colNameCollection.IndexOf(name) == colNameCollection.Count - 1) { // 分隔线 using (pen = new Pen(Color.FromArgb(229, 229, 229))) { var rtBounds = e.CellBounds; e.Graphics.DrawLine(pen, rtBounds.Right - 1, rtBounds.Top + 1, rtBounds.Right - 1, rtBounds.Bottom - 2); } } } else { //分割多级表头 using (pen = new Pen(/*dgv.GridColor*/Color.FromArgb(229, 229, 229))) { //水平分隔线 e.Graphics.DrawLine(pen, nLeft, nHeight, nLeft + nWidth, nHeight); //垂直分隔线 var rtBounds = e.CellBounds; if (colNameCollection.IndexOf(name) == colNameCollection.Count - 1) e.Graphics.DrawLine(pen, rtBounds.Right - 1, rtBounds.Top + 1, rtBounds.Right - 1, rtBounds.Bottom - 2); else e.Graphics.DrawLine(pen, rtBounds.Right - 1, nHeight, rtBounds.Right - 1, rtBounds.Bottom - 2); } //绘制二级表头文字 using (brush = new SolidBrush(e.CellStyle.ForeColor)) { SizeF textSize = TextRenderer.MeasureText(dgv.Columns[e.ColumnIndex].HeaderText, e.CellStyle.Font); int nSubTop = nTop + nHeight; int nSubLeft = e.CellBounds.Left; int nSubWidth = e.CellBounds.Width; int nSubHeight = nHeight; PointF point = new PointF(nSubLeft + 6, nSubTop + (nSubHeight - textSize.Height) / 2); if (e.CellStyle.Alignment.ToString().Contains("Center")) point.X = nSubLeft + (nSubWidth - textSize.Width) / 2; else if (e.CellStyle.Alignment.ToString().Contains("Right")) point.X = nSubLeft + nSubWidth - textSize.Width - 6; if (e.CellStyle.Alignment.ToString().Contains("Top")) point.Y = nSubTop + 4; else if (e.CellStyle.Alignment.ToString().Contains("Bottom")) point.Y = nSubTop + nSubHeight - textSize.Height - 4; e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; e.Graphics.DrawString(dgv.Columns[e.ColumnIndex].HeaderText, e.CellStyle.Font, brush, point); } } //绘制合并表头名称,只在最后绘制一次 if (colNameCollection.IndexOf(name) == colNameCollection.Count - 1) { using (brush = new SolidBrush(e.CellStyle.ForeColor)) { SizeF textSize = TextRenderer.MeasureText(headerText, e.CellStyle.Font); //单元列移出可见范围后将不再移动,需要强制改变绘制文字的位置 if (nLeft < 0) nLeft = e.CellBounds.Right - nWidth; PointF point = new PointF(nLeft + 6, nTop + (nHeight - textSize.Height) / 2); if (e.CellStyle.Alignment.ToString().Contains("Center") || isMultiLevel) point.X = nLeft + (nWidth - textSize.Width) / 2; else if (e.CellStyle.Alignment.ToString().Contains("Right")) point.X = nLeft + nWidth - textSize.Width - 6; if (e.CellStyle.Alignment.ToString().Contains("Top")) point.Y = nTop + 4; else if (e.CellStyle.Alignment.ToString().Contains("Bottom")) point.Y = nTop + nHeight - textSize.Height - 4; e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; e.Graphics.DrawString(headerText, e.CellStyle.Font, brush, point); } } //e.set_Handled(true); e.Handled = true; // 告知系统不再处理表头单元格绘制事件 } } }; } public static void AddMergeColumn(this DataGridView dgv, List colNameCollection, Color? VerGridColor = null, Color? VerGridSelectColor = null) { int nHeight = 0; int nLeft = 0; int nTop = 0; int nWidth = 0; //合并列中某一列的列宽变化时,强制重绘表头 dgv.ColumnWidthChanged += (s, e) => { if (colNameCollection.Contains(e.Column.Name)) { foreach (var columnName in colNameCollection) { if (dgv.Columns.Contains(columnName)) dgv.InvalidateCell(dgv.Columns[columnName].HeaderCell); // 标记单元格为需要重绘 } dgv.Update(); } }; dgv.Scroll += (s, e) => { if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll) { bool tag = false; foreach (var columnName in colNameCollection) { var bounds = dgv.Columns[columnName].HeaderCell.ContentBounds; if (bounds.Left < 10 || bounds.Right > dgv.Width - 10) { tag = true; break; } } if (tag == true) { foreach (var columnName in colNameCollection) { if (dgv.Columns.Contains(columnName)) dgv.InvalidateCell(dgv.Columns[columnName].HeaderCell); // 标记单元格为需要重绘 } dgv.Update(); } } }; //处理重绘事件 dgv.CellPainting += (s, e) => { if (e.RowIndex >=0 && e.ColumnIndex >= 0) // 重绘单元格 { string name = dgv.Columns[e.ColumnIndex].Name; if (colNameCollection.Contains(name)) { e.PaintBackground(e.CellBounds, true); // false不绘制单元格背景 e.PaintContent(e.CellBounds); // 绘制单元格内容,此处要绘制内容 Brush brush; Pen pen; if (colNameCollection.IndexOf(name) == 0) { nTop = e.CellBounds.Top; nLeft = e.CellBounds.Left; nWidth = e.CellBounds.Width; nHeight = e.CellBounds.Height; foreach (string str2 in colNameCollection) { if (!str2.Equals(name)) { nWidth += dgv.Columns[str2].Width; } } } //填充背景(覆盖原来的分隔线) //Rectangle rtTmp = new Rectangle(nLeft, nTop, nWidth, nHeight); //using (brush = new SolidBrush(/*e.CellStyle.BackColor*/dgv.BackgroundColor)) //{ // var rtBounds = e.CellBounds; // rtBounds.Height -= 1; // e.Graphics.FillRectangle(brush, rtBounds); //} if (colNameCollection.IndexOf(name) < colNameCollection.Count - 1) { var penColor = VerGridColor; // 分隔线 if (penColor == null) { //VerGridColor = Color.FromArgb(229, 229, 229); penColor = e.RowIndex % 2 == 0 ? dgv.DefaultCellStyle.BackColor : dgv.AlternatingRowsDefaultCellStyle.BackColor; } var penSelectColor = VerGridSelectColor; if (penSelectColor == null) //VerGridColorSelect = Color.FromArgb(129, 129, 129); penSelectColor = dgv.DefaultCellStyle.SelectionBackColor; if ((dgv.Rows[e.RowIndex].Cells[e.ColumnIndex]).Selected) { using (pen = new Pen(penSelectColor.Value)) { var rtBounds = e.CellBounds; e.Graphics.DrawLine(pen, rtBounds.Right - 1, rtBounds.Top, rtBounds.Right - 1, rtBounds.Bottom - 2); } } else { using (pen = new Pen(penColor.Value)) { var rtBounds = e.CellBounds; e.Graphics.DrawLine(pen, rtBounds.Right - 1, rtBounds.Top, rtBounds.Right - 1, rtBounds.Bottom - 2); } } } //e.set_Handled(true); e.Handled = true; // 告知系统不再处理表头单元格绘制事件 } } }; } } }