切换DataGridView列中所有复选框的状态






4.96/5 (66投票s)
本文介绍了如何切换特定 DataGridView 列中所有复选框的状态。

目录
引言
一年半前,我写了一篇文章,选择/取消选择 GridView 中的所有复选框,适用于 Web Forms。上个月,我得到了一个机会,为 Windows Forms 的 DataGridView
控件实现相同的功能。最初,我以为它会像 Web Forms 的 GridView
一样简单,但事实并非如此。对于 Windows Forms 的 DataGridView
控件来说,它有点棘手。例如,在 DataGridView
控件的列中添加标题 CheckBox
并不是一项简单的工作。因此,在进行了大量研究并花费大量时间研究控件的功能后,我终于得到了以下解决方案。欢迎所有修改和澄清!
在 DataGridView 列中添加行复选框
要在 DataGridView
列中添加行 CheckBoxes
,我添加了一个 DataGridViewCheckBoxColumn
列控件。我还将 DataGridView
[dgvSelectAll
] 的 AllowUserToAddRows
和 AllowUserToDeleteRows
属性设置为 false
,如下所示:
dgvSelectAll.AllowUserToAddRows = false;
dgvSelectAll.AllowUserToDeleteRows = false;
在 DataGridView 列中添加标题复选框
正如我之前所说,在 DataGridView
列中添加标题 CheckBox
有点棘手。我通过 Windows Form 的 Load
事件调用 AddHeaderCheckBox
方法,在 DataGridView
列中添加了一个标题 CheckBox
[HeaderCheckBox
],如下所示:
private void frmSelectAll_Load(object sender, EventArgs e)
{
AddHeaderCheckBox();
…
}
我稍后会解释 AddHeaderCheckBox
方法。
附加标题复选框的 MouseClick 和 KeyUp 事件
我通过 Windows Form 的 Load
事件连接了标题 CheckBox
的 MouseClick
和 KeyUp
事件,如下所示:
private void frmSelectAll_Load(object sender, EventArgs e)
{
…
HeaderCheckBox.KeyUp += new KeyEventHandler(HeaderCheckBox_KeyUp);
HeaderCheckBox.MouseClick += new MouseEventHandler(HeaderCheckBox_MouseClick);
…
}
标题复选框的 MouseClick 事件处理程序
每当我们点击标题 CheckBox
时,都会触发 MouseClick
事件。在这里,通过将标题 CheckBox
的引用作为参数传递来调用 HeaderCheckBoxClick
方法。我稍后会讨论 HeaderCheckBoxClick
方法。
private void HeaderCheckBox_MouseClick(object sender, MouseEventArgs e)
{
HeaderCheckBoxClick((CheckBox)sender);
}
标题复选框的 KeyUp 事件处理程序
如果标题 CheckBox
获得焦点,每当我们释放标题 CheckBox
上的键时,都会触发 KeyUp
事件。在这里,如果此事件是由空格键引发的,则通过将标题 CheckBox
的引用作为参数来调用 HeaderCheckBoxClick
方法。
private void HeaderCheckBox_KeyUp(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Space)
HeaderCheckBoxClick((CheckBox)sender);
}
附加 DataGridView 的 CellValueChanged、CurrentCellDirtyStateChanged 和 CellPainting 事件
我通过 Windows Form 的 Load
事件分别连接了 DataGridView
的 CellValueChanged
、CurrentCellDirtyStateChanged
和 CellPainting
事件,如下所示:
private void frmSelectAll_Load(object sender, EventArgs e)
{
...
dgvSelectAll.CellValueChanged +=
new DataGridViewCellEventHandler(dgvSelectAll_CellValueChanged);
dgvSelectAll.CurrentCellDirtyStateChanged +=
new EventHandler(dgvSelectAll_CurrentCellDirtyStateChanged);
dgvSelectAll.CellPainting +=
new DataGridViewCellPaintingEventHandler(dgvSelectAll_CellPainting);
...
}
DataGridView 的 CellValueChanged 事件处理程序
每当 DataGridView
单元格的值发生变化时,都会触发 CellValueChanged
事件。在这里,如果未点击标题 CheckBox
,则通过传递引发此事件的 DataGridViewCheckBoxCell
的引用来调用 RowCheckBoxClick
方法。我稍后会描述 RowCheckBoxClick
方法。
private void dgvSelectAll_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (!IsHeaderCheckBoxClicked)
RowCheckBoxClick((DataGridViewCheckBoxCell)dgvSelectAll[e.ColumnIndex, e.RowIndex]);
}
DataGridView 的 CellPainting 事件处理程序
每当需要绘制 DataGridView
单元格时,都会触发 CellPainting
事件。基本上,我处理此事件是为了在需要时重置标题 CheckBox
在 DataGridView
中的位置。在这里,首先确保要绘制的单元格是第一列的标题;然后,通过传递 e.ColumnIndex
和 e.RowIndex
作为参数来调用 ResetHeaderCheckBoxLocation
方法。我稍后会讨论 ResetHeaderCheckBoxLocation
方法的详细信息。
private void dgvSelectAll_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex == -1 && e.ColumnIndex == 0)
ResetHeaderCheckBoxLocation(e.ColumnIndex, e.RowIndex);
}
DataGridView 的 CurrentCellDirtyStateChanged 事件处理程序
每当 DataGridView
单元格的状态因其内容的变化而变化时,都会触发 CurrentCellDirtyStateChanged
事件。基本上,此事件调用 CommitEdit
方法以引发 CellValueChanged
事件并确定 DataGridViewCheckBoxCell
的当前值。
private void dgvSelectAll_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dgvSelectAll.CurrentCell is DataGridViewCheckBoxCell)
dgvSelectAll.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
AddHeaderCheckBox 方法
AddHeaderCheckBox
方法用于在 DataGridView
控件中添加标题 CheckBox
控件。基本上,此方法不会在特定的 DataGridView
列中添加 CheckBox
控件;它只是在 DataGridView
中添加一个标题 CheckBox
控件。这是 ResetLocation
方法的工作。
private void AddHeaderCheckBox()
{
HeaderCheckBox = new CheckBox();
HeaderCheckBox.Size = new Size(15, 15);
//Add the CheckBox into the DataGridView
this.dgvSelectAll.Controls.Add(HeaderCheckBox);
}
ResetLocation 方法
此方法负责设置标题 CheckBox
在特定 DataGridView
列中的位置。在此方法中,我首先获取特定标题单元格的单元格边界,然后计算标题 CheckBox
的坐标,以更改其位置,使其停留在特定 DataGridview
列的标题上。最后,我设置标题 CheckBox
在 DataGridview
中的位置。
private void ResetLocation(int ColumnIndex, int RowIndex)
{
//Get the column header cell bounds
Rectangle oRectangle =
this.dgvSelectAll.GetCellDisplayRectangle(ColumnIndex, RowIndex, true);
Point oPoint = new Point();
oPoint.X = oRectangle.Location.X + (oRectangle.Width - HeaderCheckBox.Width) / 2 + 1;
oPoint.Y = oRectangle.Location.Y + (oRectangle.Height - HeaderCheckBox.Height) / 2 + 1;
//Change the location of the CheckBox to make it stay on the header
HeaderCheckBox.Location = oPoint;
}
HeaderCheckBoxClick 方法
此方法用于根据标题 CheckBox
的状态切换特定 DataGridView
列的所有行 CheckBox
的状态。在开始此过程之前,我将全局变量 IsHeaderCheckBoxClicked
设置为 false
,表示行 CheckBox
的状态即将被切换。每次行 CheckBox
的状态改变时,都会触发 DataGridView
的 CellValueChanged
事件。在此事件中,如果 IsHeaderCheckBoxClicked
的值被发现为 false
,则会调用 RowCheckBoxClick
方法。现在,在切换行 CheckBox
的状态后,我调用 DataGridView
的 RefreshEdit
方法,以便在单元格处于编辑模式时,用底层单元格的值刷新当前单元格的值,并丢弃任何先前的值。接下来,根据标题 CheckBox
的状态设置全局变量 TotalCheckedCheckBoxes
的值。最后,我恢复全局变量 IsHeaderCheckBoxClicked
的值。
private void HeaderCheckBoxClick(CheckBox HCheckBox)
{
IsHeaderCheckBoxClicked = true;
foreach (DataGridViewRow Row in dgvSelectAll.Rows)
((DataGridViewCheckBoxCell)Row.Cells["chkBxSelect"]).Value = HCheckBox.Checked;
dgvSelectAll.RefreshEdit();
TotalCheckedCheckBoxes = HCheckBox.Checked ? TotalCheckBoxes : 0;
IsHeaderCheckBoxClicked = false;
}
RowCheckBoxClick 方法
此方法根据 DataGridView
列的所有 CheckBoxes
是否被选中或取消选中来检查/取消选中标题 CheckBox
的状态。
private void RowCheckBoxClick(DataGridViewCheckBoxCell RCheckBox)
{
if (RCheckBox != null)
{
//Modify Counter;
if ((bool)RCheckBox.Value && TotalCheckedCheckBoxes < TotalCheckBoxes)
TotalCheckedCheckBoxes++;
else if (TotalCheckedCheckBoxes > 0)
TotalCheckedCheckBoxes--;
//Change state of the header CheckBox.
if (TotalCheckedCheckBoxes < TotalCheckBoxes)
HeaderCheckBox.Checked = false;
else if (TotalCheckedCheckBoxes == TotalCheckBoxes)
HeaderCheckBox.Checked = true;
}
}
BindGridView 方法
此方法用于绑定 DataGridView
以及初始化全局变量 TotalCheckBoxes
和 TotalCheckedCheckBoxes
。
private void BindGridView()
{
dgvSelectAll.DataSource = GetDataSource();
TotalCheckBoxes = dgvSelectAll.RowCount;
TotalCheckedCheckBoxes = 0;
}
总结
这就是我为实现此功能所采用的方法。如果任何人有不同的想法或建议来进一步改进此功能,请与我分享。我已在安装了 VS 2008 和 Win XP SP3 的机器上创建并测试了此演示应用程序。
历史
- 2009 年 10 月 1 日 -- 文章更新(修改了引言部分)
- 2009 年 9 月 25 日 -- 文章更新(添加了目录)
- 2009 年 9 月 18 日 -- 原始版本发布