如何将Checkbox作为dataGridView的ColumnHeader

我正在用C#VS2005开发一个窗口应用程序。 我有一个dataGridView,其中第一列有Checkboxes。 现在我希望Column标题也是一个CheckBox,如果我选择列中的所有Checkboxex应该被选中。 我怎样才能做到这一点。? 我参考了Code Project链接

但如果我使用它,如果我点击FirstCell(而不是标题),所有下面的单元格都会被选中。 但我想在Column标题中有一个CheckBox。 我怎样才能做到这一点。?

我还需要在DataGridView列的列标题中有一个CheckBox 。 我是这样做的:

  • 创建一个inheritance自DataGridViewColumnHeaderCell的类
  • 在内部使用System.Windows.Forms.CheckBox来存储已检查状态并提供OS样式的可视化CheckBox表示。
  • 使用Bitmap作为缓冲区并在其上绘制常规CheckBox (使用CheckBox.DrawToBitmap
  • 覆盖DataGridViewColumnHeaderCell.Paint ,如有必要,在将缓冲区绘制到Paint提供的Graphics之前更新缓冲区
  • 在派生的DataGridViewColumnHeaderCell上提供Checked属性,还提供CheckedChanged事件
  • 在填充DataGridViewColumnHeaderCell ,在列的HeaderCell替换派生的DataGridViewColumnHeaderCell
  • 仅当单击列标题时,选中并取消选中CheckBox ,仅当鼠标单击位于CheckBox的边界内时
  • 通过侦听CheckedChanged事件,更新底层数据对象然后调用ResetBindings来更新DataGridView ,在派生类之外实现check-all / uncheck-all

这是我写的类,它是从DataGridViewColumnHeaderCell派生的:

 class DataGridViewCheckBoxColumnHeaderCell : DataGridViewColumnHeaderCell { private Bitmap buffer; private CheckBox checkBox; private Rectangle checkBoxBounds; public DataGridViewCheckBoxColumnHeaderCell() { this.checkBox = new CheckBox(); } public event EventHandler CheckedChanged; public bool Checked { get { return this.checkBox.Checked; } set { if (!this.Checked == value) { this.checkBox.Checked = value; if (this.buffer != null) { this.buffer.Dispose(); this.buffer = null; } this.OnCheckedChanged(EventArgs.Empty); if (this.DataGridView != null) { this.DataGridView.Refresh(); } } } } protected override void Paint( Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates dataGridViewElementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { // Passing String.Empty in place of // value and formattedValue prevents // this header cell from having text. base.Paint( graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, String.Empty, String.Empty, errorText, cellStyle, advancedBorderStyle, paintParts); if (this.buffer == null || cellBounds.Width != this.buffer.Width || cellBounds.Height != this.buffer.Height) { this.UpdateBuffer(cellBounds.Size); } graphics.DrawImage(this.buffer, cellBounds.Location); } protected override Size GetPreferredSize( Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex, Size constraintSize) { return this.checkBox.GetPreferredSize(constraintSize); } protected override void OnMouseClick(DataGridViewCellMouseEventArgs e) { if (e.Button == MouseButtons.Left && this.checkBoxBounds.Contains(e.Location)) { this.Checked = !this.Checked; } base.OnMouseClick(e); } private void UpdateBuffer(Size size) { Bitmap updatedBuffer = new Bitmap(size.Width, size.Height); this.checkBox.Size = size; if (this.checkBox.Size.Width > 0 && this.checkBox.Size.Height > 0) { Bitmap renderedCheckbox = new Bitmap( this.checkBox.Width, this.checkBox.Height); this.checkBox.DrawToBitmap( renderedCheckbox, new Rectangle(new Point(), this.checkBox.Size)); MakeTransparent(renderedCheckbox, this.checkBox.BackColor); Bitmap croppedRenderedCheckbox = AutoCrop( renderedCheckbox, Color.Transparent); // TODO implement alignment, right now it is always // MiddleCenter regardless of this.Style.Alignment this.checkBox.Location = new Point( (updatedBuffer.Width - croppedRenderedCheckbox.Width) / 2, (updatedBuffer.Height - croppedRenderedCheckbox.Height) / 2); Graphics updatedBufferGraphics = Graphics.FromImage(updatedBuffer); updatedBufferGraphics.DrawImage( croppedRenderedCheckbox, this.checkBox.Location); this.checkBoxBounds = new Rectangle( this.checkBox.Location, croppedRenderedCheckbox.Size); renderedCheckbox.Dispose(); croppedRenderedCheckbox.Dispose(); } if (this.buffer != null) { this.buffer.Dispose(); } this.buffer = updatedBuffer; } protected virtual void OnCheckedChanged(EventArgs e) { EventHandler handler = this.CheckedChanged; if (handler != null) { handler(this, e); } } // The methods below are helper methods for manipulating Bitmaps private static void MakeTransparent(Bitmap bitmap, Color transparencyMask) { int transparencyMaskArgb = transparencyMask.ToArgb(); int transparentArgb = Color.Transparent.ToArgb(); List deadColumns = new List(); for (int x = 0; x = 0; x--) { if (deadColumns.Count == bitmap.Height) { break; } for (int y = bitmap.Height - 1; y >= 0; y--) { if (deadColumns.Contains(y)) { continue; } int pixel = bitmap.GetPixel(x, y).ToArgb(); if (pixel == transparencyMaskArgb) { bitmap.SetPixel(x, y, Color.Transparent); } else if (pixel != transparentArgb) { deadColumns.Add(y); break; } } } } public static Bitmap AutoCrop(Bitmap bitmap, Color backgroundColor) { Size croppedSize = bitmap.Size; Point cropOrigin = new Point(); int backgroundColorToArgb = backgroundColor.ToArgb(); for (int x = bitmap.Width - 1; x >= 0; x--) { bool allPixelsAreBackgroundColor = true; for (int y = bitmap.Height - 1; y >= 0; y--) { if (bitmap.GetPixel(x, y).ToArgb() != backgroundColorToArgb) { allPixelsAreBackgroundColor = false; break; } } if (allPixelsAreBackgroundColor) { croppedSize.Width--; } else { break; } } for (int y = bitmap.Height - 1; y >= 0; y--) { bool allPixelsAreBackgroundColor = true; for (int x = bitmap.Width - 1; x >= 0; x--) { if (bitmap.GetPixel(x, y).ToArgb() != backgroundColorToArgb) { allPixelsAreBackgroundColor = false; break; } } if (allPixelsAreBackgroundColor) { croppedSize.Height--; } else { break; } } for (int x = 0; x = 0 && xWhole = 0) { bitmapSection.SetPixel(x, y, bitmap.GetPixel(xWhole, yWhole)); } else { bitmapSection.SetPixel(x, y, Color.Transparent); } } } return bitmapSection; } } 

上面的解决方案很好,但也有一种更简单的方法! 只需添加这两种方法,然后就可以得到你想要的!

首先在代码中添加一个show_chkBox方法,然后在表单的onload函数中或在创建DataGridView之后调用它:

  private void show_chkBox() { Rectangle rect = dataGridView1.GetCellDisplayRectangle(0, -1, true); // set checkbox header to center of header cell. +1 pixel to position rect.Y = 3; rect.X = rect.Location.X + (rect.Width/4); CheckBox checkboxHeader = new CheckBox(); checkboxHeader.Name = "checkboxHeader"; //datagridview[0, 0].ToolTipText = "sdfsdf"; checkboxHeader.Size = new Size(18, 18); checkboxHeader.Location = rect.Location; checkboxHeader.CheckedChanged += new EventHandler(checkboxHeader_CheckedChanged); dataGridView1.Controls.Add(checkboxHeader); } 

然后你会在标题中有复选框。

对于选择问题,只需添加以下代码:

 private void checkboxHeader_CheckedChanged(object sender, EventArgs e) { CheckBox headerBox = ((CheckBox)dataGridView1.Controls.Find("checkboxHeader", true)[0]); int index = 0; for (int i = 0; i < dataGridView1.RowCount; i++) { dataGridView1.Rows[i].Cells[0].Value = headerBox.Checked; } } 

如果选择@Ehsan解决方案,则必须知道如果选中复选框单元格,则不会更新复选框UI。 之后你需要调用RefreshEdit()。

它只发生在控件是datagridview的子控件时。 出于某种原因,当它是子控件时,所选单元格复选框无法通过它们自己刷新UI。

感谢Ehsan的简单方法,对我来说很好。 对于这个问题,只有一个CheckBox总是在左上角,我为每个CheckBox添加一个名称后缀并解决了。 另外,我想通过直接转换对象发送者来稍微修改事件处理方法,因为它在创建时非常具体(除非此方法用于处理其他类型的控件事件)。

 private string[] _colLst = columNameArray; private void AddCheckBoxGridViewHeader() { for (int ndx = 0; ndx < _colLst.Length; ndx++) { var rect = dtgv1.GetCellDisplayRectangle(ndx, -1, true); var x = rect.X + (rect.Width * 4 / 5); var y = 3; Rectangle nrect = new Rectangle(x, y, rect.Width, rect.Height); CheckBox checkboxHeader = new CheckBox(); checkboxHeader.BackColor = Color.Transparent; checkboxHeader.Name = "checkboxHeader" + ndx; checkboxHeader.Size = new Size(18, 18); checkboxHeader.Location = nrect.Location; checkboxHeader.CheckedChanged += new EventHandler(checkboxHeader_CheckedChanged); dtgv1.Controls.Add(checkboxHeader); } } private void checkboxHeader_CheckedChanged(object sender, EventArgs e) { //CheckBox headerBox = ((CheckBox)dtgv1.Controls.Find("checkboxHeader", true)[0]); var headerBox = (CheckBox)sender; var b = headerBox.Checked; var c = int.Parse(headerBox.Name.Replace("checkboxHeader", "")); for (int i = 0; i < dtgv1.RowCount; i++) { dtgv1.Rows[i].Cells[c].Style = new DataGridViewCellStyle(); dtgv1.Rows[i].Cells[c].Style.BackColor = (b)? Color.Salmon : Color.White; } } 

所以 – 为了解决最重要的复选框没有显示为已选中(即使它是),我最终编辑你的事件如下:

private void checkboxHeader_CheckedChanged(object sender,EventArgs e){// CheckBox headerBox =((CheckBox)dtgv1.Controls.Find(“checkboxHeader”,true)[0]);

  var headerBox = (CheckBox)sender; var b = headerBox.Checked; var c = int.Parse(headerBox.Name.Replace("checkboxHeader", "")); for (int i = 0; i < dgvSources_fuzzyID.RowCount; i++) { dgvSources_fuzzyID.Rows[i].Cells[0].Value = headerBox.Checked; ***dgvSources_fuzzyID.RefreshEdit();*** } } 

这就是最终为我修好的......