上次从CodeProject上发现了一个老外写的开源的带CheckBox列头的类,当时就将文章翻译了过来并做成了一个小Demo,供大家参考,最近在开发中需要用到这个类,因此加以了改进,上次还有一个兄弟提到问怎样实现取消列表中选择的一行,列头的全选CheckBox也能处于不选中状态。这是一个很好的问题,我最近几天花了些时间,将其进行了些修改。终于可以实现这一功能了。废话不多说了,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace chbDGV
{
public delegate void CheckBoxClickedHandler(bool state);
/// <summary>
/// 改变列头的CheckBox的状态
/// </summary>
/// <param name="state"></param>
public delegate void ChangeCheckBoxStatusHandler(bool state);
public class DataGridViewCheckBoxHeaderCellEventArgs : EventArgs
{
bool _bChecked;
public DataGridViewCheckBoxHeaderCellEventArgs(bool bChecked)
{
_bChecked = bChecked;
}
public bool Checked
{
get { return _bChecked; }
}
}
class DatagridViewCheckBoxHeaderCell : DataGridViewColumnHeaderCell
{
Point checkBoxLocation;
Size checkBoxSize;
bool _checked = false;
Point _cellLocation = new Point();
System.Windows.Forms.VisualStyles.CheckBoxState _cbState =
System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal;
public event CheckBoxClickedHandler OnCheckBoxClicked;
public event ChangeCheckBoxStatusHandler OnChangeCheckBoxStatusHandler;
public DatagridViewCheckBoxHeaderCell()
{
}
protected override void Paint(System.Drawing.Graphics graphics,
System.Drawing.Rectangle clipBounds,
System.Drawing.Rectangle cellBounds,
int rowIndex,
DataGridViewElementStates dataGridViewElementState,
object value,
object formattedValue,
string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex,
dataGridViewElementState, value,
formattedValue, errorText, cellStyle,
advancedBorderStyle, paintParts);
Point p = new Point();
Size s = CheckBoxRenderer.GetGlyphSize(graphics,
System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
p.X = cellBounds.Location.X +
(cellBounds.Width / 2) - (s.Width / 2);
p.Y = cellBounds.Location.Y +
(cellBounds.Height / 2) - (s.Height / 2);
_cellLocation = cellBounds.Location;
checkBoxLocation = p;
checkBoxSize = s;
if (_checked)
_cbState = System.Windows.Forms.VisualStyles.
CheckBoxState.CheckedNormal;
else
_cbState = System.Windows.Forms.VisualStyles.
CheckBoxState.UncheckedNormal;
CheckBoxRenderer.DrawCheckBox
(graphics, checkBoxLocation, _cbState);
}
protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
{
Point p = new Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y);
if (p.X >= checkBoxLocation.X && p.X <=
checkBoxLocation.X + checkBoxSize.Width
&& p.Y >= checkBoxLocation.Y && p.Y <=
checkBoxLocation.Y + checkBoxSize.Height)
{
_checked = !_checked;
if (OnCheckBoxClicked != null)
{
OnCheckBoxClicked(_checked);
this.DataGridView.InvalidateCell(this);
}
}
base.OnMouseClick(e);
}
/// <summary>
/// 改变列头CheckBox的状态的事件
/// </summary>
/// <param name="NewStatus"></param>
public void OnChangeCheckBoxStatus(bool NewStatus)
{
if (OnCheckBoxClicked != null)
{
_checked = NewStatus;
if (OnChangeCheckBoxStatusHandler != null)
{
OnChangeCheckBoxStatusHandler(NewStatus);
}
if (this.DataGridView != null)
{
this.DataGridView.InvalidateCell(this);
}
}
}
}
}
测试的代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace chbDGV
{
public partial class frmTestDGV : Form
{
DataGridViewCheckBoxColumn colCB = new DataGridViewCheckBoxColumn();
DatagridViewCheckBoxHeaderCell cbHeader = new DatagridViewCheckBoxHeaderCell();
DataTable dt = new DataTable();
public frmTestDGV()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
BindDGV();
}
public override void Refresh()
{
base.Refresh();
}
private void cbHeader_OnCheckBoxClicked(bool Status)
{
for (int i = 0; i < dgvTest.Rows.Count; i++)
{
dt.Rows[i]["Select"] = Status;
}
}
private void BindDGV()
{
dt.Columns.Add("Select");
dt.Columns.Add("ID");
dt.Columns.Add("Code");
dt.Columns.Add("Name");
dt.Columns.Add("Desc");
for (int i = 0; i < 5; i++)
{
dt.Rows.Add();
dt.Rows[i][0] = false;
dt.Rows[i][1] = "100"+i.ToString();
dt.Rows[i][2] = "Lucy1001"+i.ToString();
dt.Rows[i][3] = "KateTest"+i.ToString();
dt.Rows[i][4] = "remark...";
}
colCB.HeaderCell = cbHeader;
dgvTest.Columns.Insert(0, colCB);
cbHeader.OnCheckBoxClicked +=
new CheckBoxClickedHandler(cbHeader_OnCheckBoxClicked);
dgvTest.AllowUserToAddRows = false;
dgvTest.AutoGenerateColumns = false;
dgvTest.DataSource = dt;
this.colCB.DataPropertyName = "Select";
this.ID.DataPropertyName = "ID";
this.Code.DataPropertyName = "Code";
this.TestName.DataPropertyName = "Name";
this.Desc.DataPropertyName = "Desc";
}
/// <summary>
/// 点击DataGridView的行
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dgv_CellClick(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgvv = ((DataGridView)sender);
if (dgvTest.CurrentCell.OwningColumn.DataPropertyName == "Select")
{
if (e.RowIndex != -1)
{
this.SetSelected(dgvv, e.RowIndex);
}
}
}
/// <summary>
/// 设置DataGridView的选择
/// </summary>
/// <param name="dgvb"></param>
/// <param name="rowIndex"></param>
private void SetSelected(DataGridView dgvb, int rowIndex)
{
if (dgvb.Rows[rowIndex] != null)
{
if (dgvb.Rows[rowIndex].Cells[0].Value != null && dgvb.Rows[rowIndex].Cells[0].Value.ToString() != "")
{
bool status = !Convert.ToBoolean(dgvb.Rows[rowIndex].Cells[0].Value);
dt.Rows[rowIndex][0] = status;
dgvb.Rows[rowIndex].Cells[0].Value = status;
for (int i = 0; i < dgvb.Rows.Count; i++)
{
if (dgvb.Rows[i].Cells[0].Value != null && dgvb.Rows[i].Cells[0].Value.ToString() != "")
{
status = Convert.ToBoolean(dgvb.Rows[i].Cells[0].Value);
if (!status)
{
cbHeader.OnChangeCheckBoxStatus(status);
break;
}
}
}
if (status)
{
cbHeader.OnChangeCheckBoxStatus(status);
}
dgvb.EndEdit();
}
else
{
bool status1 = false;
dgvb.Rows[rowIndex].Cells[0].Value = dt.Rows[rowIndex][0].ToString();
for (int i = 0; i < dgvb.Rows.Count; i++)
{
if (dgvb.Rows[i].Cells[0].Value != null && dgvb.Rows[i].Cells[0].Value.ToString() != "")
{
status1 = Convert.ToBoolean(dgvb.Rows[i].Cells[0].Value);
if (!status1)
{
cbHeader.OnChangeCheckBoxStatus(status1);
break;
}
}
}
if (status1)
{
cbHeader.OnChangeCheckBoxStatus(status1);
}
dgvb.EndEdit();
}
}
}
}
}
代码比较简单,我就没有加很多注释,也不介绍了。代码我会放在我的资源中供大家下载,资源名为:带CheckBox列头有全选择功能的DataGridView二。