在DataGridView中实现Checkbox的全选的方法就是在列头画一个checkbox, 并给其一个事件.
这个之前很多blog都有写, 这里就不多废话了, codeproject上面有示例代码.
这里我们再多做一层的封装,将其封装成一个控件,这样的话, 我们就可以最大程度上的复用, 而不需要老是重复写同样的, 无聊的代码了!
思路如下:
继承DataGridViewCheckBoxColumn类, 更改它的headerCell的样式. 添加cellValueChanged时间,使在进行复选框选择的时候可以触发事件,从而进行处理.
继承DataGridViewColumnHeaderCell类, 重新绘制一个带CheckBox的HeaderCell
话不多说直接上代码了, 如果有不懂的欢迎留言:
public class DataGridViewCheckBoxColumnSelectAll : DataGridViewCheckBoxColumn { private DatagridViewCheckBoxHeaderCell headerCell; private bool loaded; public event CheckBoxClickedHandler OnCheckBoxClicked; int TotalCheckedCheckBoxes = 0; bool IsHeaderCheckBoxClicked = false; public DataGridViewCheckBoxColumnSelectAll() { this.headerCell = new DatagridViewCheckBoxHeaderCell(); base.HeaderCell = this.headerCell; this.headerCell.OnCheckBoxClicked += new CheckBoxClickedHandler(this.headerCell_OnCheckBoxClicked); this.loaded = false; } public DataGridViewCheckBoxColumnSelectAll(bool threeState) : base(threeState) { this.headerCell = new DatagridViewCheckBoxHeaderCell(); base.HeaderCell = this.headerCell; } /// <summary> /// 在DataGridView改变时进行事件的绑定 /// </summary> protected override void OnDataGridViewChanged() { if (this.DataGridView!=null) { this.DataGridView.CellValueChanged -= DataGridView_CellValueChanged; this.DataGridView.CellValueChanged += DataGridView_CellValueChanged; this.DataGridView.CurrentCellDirtyStateChanged -= DataGridView_CurrentCellDirtyStateChanged; this.DataGridView.CurrentCellDirtyStateChanged += DataGridView_CurrentCellDirtyStateChanged; } } /// <summary> /// 在复选的时候进行判断. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void DataGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex>=0&&e.ColumnIndex>=0) { if (!IsHeaderCheckBoxClicked) RowCheckBoxClick((DataGridViewCheckBoxCell)this.DataGridView[e.ColumnIndex, e.RowIndex]); } } /// <summary> /// 在复选框被选中的时候触发该事件, 该事件用于触发ValueChanged事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DataGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e) { if (this.DataGridView.CurrentCell is DataGridViewCheckBoxCell) this.DataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit); } /// <summary> /// 复选框被点击时所需要做的操作 /// </summary> /// <param name="checkBox"></param> private void RowCheckBoxClick(DataGridViewCheckBoxCell checkBox) { var head = this.headerCell as DatagridViewCheckBoxHeaderCell; if (checkBox != null) { //计算所有被选中的行的数量 if ((bool)checkBox.Value && TotalCheckedCheckBoxes < this.DataGridView.RowCount) TotalCheckedCheckBoxes++; else if (TotalCheckedCheckBoxes > 0) TotalCheckedCheckBoxes--; //当所有复选框都被选中的时候,列的头上的复选框被选中, 反之则不被选中. if (TotalCheckedCheckBoxes < this.DataGridView.RowCount) head.IsChecked = false; else if (TotalCheckedCheckBoxes == this.DataGridView.RowCount) head.IsChecked = true; //强制repained head.DataGridView.InvalidateCell(head); } } /// <summary> /// 头被选中时触发OnCheckBoxClicked事件. /// </summary> /// <param name="state"></param> private void headerCell_OnCheckBoxClicked(bool state) { if (this.OnCheckBoxClicked != null) { this.OnCheckBoxClicked(state); } } }
public delegate void CheckBoxClickedHandler(bool state);
internal class DatagridViewCheckBoxHeaderCell : DataGridViewColumnHeaderCell
{
private CheckBoxState _cbState = CheckBoxState.UncheckedNormal;
private Point _cellLocation = new Point();
private bool _checked;
private Point checkBoxLocation;
private Size checkBoxSize;
public bool IsChecked
{
get
{
return _checked;
}
set
{
_checked = value;
if (this._checked)
{
this._cbState = CheckBoxState.CheckedNormal;
}
else
{
this._cbState = CheckBoxState.UncheckedNormal;
}
}
}
public event CheckBoxClickedHandler OnCheckBoxClicked;
/// <summary>
/// 点击列头的时候触发的事件,这里有个判断, 如果点击的位置是复选框则触发OnCheckBoxClicked事件.
/// </summary>
/// <param name="e"></param>
protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
{
Point point = new Point(e.X + this._cellLocation.X, e.Y + this._cellLocation.Y);
if (((point.X >= this.checkBoxLocation.X) && (point.X <= (this.checkBoxLocation.X + this.checkBoxSize.Width))) && ((point.Y >= this.checkBoxLocation.Y) && (point.Y <= (this.checkBoxLocation.Y + this.checkBoxSize.Height))))
{
this._checked = !this._checked;
bool temp = this._checked;
if (this.OnCheckBoxClicked != null)
{
this.OnCheckBoxClicked(this._checked);
base.DataGridView.InvalidateCell(this);
}
foreach (DataGridViewRow row in base.DataGridView.Rows)
{
((DataGridViewCheckBoxCell)row.Cells[e.ColumnIndex]).Value = temp;
}
base.DataGridView.RefreshEdit();
}
base.OnMouseClick(e);
}
/// <summary>
/// 绘制一个CheckBox
/// </summary>
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)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
Point point = new Point();
Size glyphSize = CheckBoxRenderer.GetGlyphSize(graphics, CheckBoxState.UncheckedNormal);
point.X = (cellBounds.Location.X + (cellBounds.Width / 2)) - (glyphSize.Width / 2);
point.Y = (cellBounds.Location.Y + (cellBounds.Height / 2)) - (glyphSize.Height / 2);
this._cellLocation = cellBounds.Location;
this.checkBoxLocation = point;
this.checkBoxSize = glyphSize;
if (this._checked)
{
this._cbState = CheckBoxState.CheckedNormal;
}
else
{
this._cbState = CheckBoxState.UncheckedNormal;
}
CheckBoxRenderer.DrawCheckBox(graphics, this.checkBoxLocation, this._cbState);
}
}
源码位置:
http://pan.baidu.com/s/1jGJzErs