为DataGridView 添加复选框,实现全选功能

原文链接:http://www.codeproject.com/Articles/42437/Toggling-the-States-of-all-CheckBoxes-Inside-a-Dat


1、 指定DataGridView的第一列为DataGridViewCheckBoxColumn

2、 为第一列的标题栏添加一个CheckBox,假设为HeaderCheckBox
同时为HeaderCheckBox定义好 MouseClick 和 KeyUp 事件
private void frmSelectAll_Load(object sender, EventArgs e) 
{
   … 
   
   AddHeaderCheckBox();
   HeaderCheckBox.KeyUp += new KeyEventHandler(HeaderCheckBox_KeyUp);
   HeaderCheckBox.MouseClick += new MouseEventHandler(HeaderCheckBox_MouseClick);
   … 
}

private void AddHeaderCheckBox()
{
    HeaderCheckBox = new CheckBox();
    HeaderCheckBox.Size = new Size(15, 15);

    //Add the CheckBox into the DataGridView
    this.dgvSelectAll.Controls.Add(HeaderCheckBox);
}

private void HeaderCheckBox_MouseClick(object sender, MouseEventArgs e) 
{
    HeaderCheckBoxClick((CheckBox)sender); 
}

private void HeaderCheckBox_KeyUp(object sender, KeyEventArgs e)
{
    if(e.KeyCode == Keys.Space)
       HeaderCheckBoxClick((CheckBox)sender);
}

private void HeaderCheckBoxClick(CheckBox HCheckBox)
{
    IsHeaderCheckBoxClicked = true;

    foreach (DataGridViewRow Row in dgvSelectAll.Rows)
        ((DataGridViewCheckBoxCell)Row.Cells[0]).Value = HCheckBox.Checked;

    dgvSelectAll.RefreshEdit();

    TotalCheckedCheckBoxes = HCheckBox.Checked ? TotalCheckBoxes : 0;

    IsHeaderCheckBoxClicked = false;
}


3、 以上代码发现HeaderCheckBox不在正确的位置显示
所以添加绘制代码,调整位置
private void frmSelectAll_Load(object sender, EventArgs e)
{
   ...
   dgvSelectAll.CellPainting += new DataGridViewCellPaintingEventHandler(dgvSelectAll_CellPainting);   
   ...
}

private void dgvSelectAll_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
   if (e.RowIndex == -1 && e.ColumnIndex == 0)
      ResetHeaderCheckBoxLocation(e.ColumnIndex, e.RowIndex);
}

private void ResetHeaderCheckBoxLocation(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;
}

4、 到此为止,第一列的显示,全选/全不选功能已经做好
此时,如果DataGridView的ReadOnly为True,则发现点击CheckBox,无法修改其选中状态
而设置ReadOnly为false,则发现可以修改CheckBox的状态,但是DataGridView处于编辑状态
private void frmSelectAll_Load(object sender, EventArgs e)
{
   ...
   dgvSelectAll.CurrentCellDirtyStateChanged += new EventHandler(dgvSelectAll_CurrentCellDirtyStateChanged);  
   ...
}


private void dgvSelectAll_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    if (dgvSelectAll.CurrentCell is DataGridViewCheckBoxCell)
        dgvSelectAll.CommitEdit(DataGridViewDataErrorContexts.Commit);
}

注意:如果仅希望第一列可以修改,其他列不能修改,可以把其他列设置为只读


5、 单击HeaderCheckBox,让DataGridView处于全选状态
然后取消部分记录的选中状态,此时HeaderCheckBox仍然为选中状态,而不是预期中的非选中状态

private void frmSelectAll_Load(object sender, EventArgs e)
{
   ...
   dgvSelectAll.CellValueChanged += new DataGridViewCellEventHandler(dgvSelectAll_CellValueChanged);
   ...
}

private void dgvSelectAll_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    if (!IsHeaderCheckBoxClicked)
        RowCheckBoxClick((DataGridViewCheckBoxCell)dgvSelectAll[e.ColumnIndex, e.RowIndex]);
}   

private void RowCheckBoxClick(DataGridViewCheckBoxCell RCheckBox)
{
    if (RCheckBox != null)
    {
        //Modifiy 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;
    }
} 

6、 IsHeaderCheckBoxClicked的作用
因为HeaderCheckBox状态的改变,会触发DataGridView的CellValueChanged事件
而DataGridView的CellValueChanged事件也会导致HeaderCheckBox状态修改
所以,这里用了一个全局变量,来避免程序进入死循环
    
在 C# DataGridView添加复选框并防止重复添加通常需要处理数据绑定和控件状态的更新。以下是步骤和一些关键点: 1. **初始化DataGridView**: 创建 DataGridView 时,将其 `AllowUserToAddRows` 和 `SelectionMode` 设置为适当的值,例如不允许用户直接添加新行,可以设置为 `AllowUserToAddRows = false`。 ```csharp DataGridView dgv = new DataGridView(); dgv.AllowUserToAddRows = false; dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect; ``` 2. **自定义列模板**: 创建一个新的 DataTemplate 或通过 `ColumnTemplate` 属性设置,其中包含复选框。使用 `DataGridViewTextBoxColumn` 的 Clone 方法创建复选框,并在 CellFormatting 事件中处理复选框的状态。 ```csharp DataGridViewTextBoxColumn checkboxColumn = new DataGridViewTextBoxColumn(); checkboxColumn.DefaultCellStyle = new DataGridViewCellStyle { EditingControlType = typeof(ToolStripMenuItem) }; dataGridView1.Columns.Add(checkboxColumn); private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { if (e.ColumnIndex == checkboxColumn.Index) { DataGridViewCheckBoxCell cell = e.Cell as DataGridViewCheckBoxCell; // 根据数据源判断是否已存在复选框 bool isChecked = // 检查当前行是否已有勾选的项,这里假设有个绑定的数据源dataRow cell.Value = dataRow.IsChecked; // 设置复选框状态 } } ``` 3. **数据源绑定**: 使用 `DataSource` 或 `DataBinding` 将数据绑定到 DataGridView 上,确保每个条目只有一项会被标记为选中。 4. **处理勾选状态更改**: 如果允许用户手动修改复选框,可以在 `CellValueChanged` 或 `CellContentClick` 事件中跟踪整个表单内哪些行的复选框已被改变。 ```csharp private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) { if (e.ColumnIndex == checkboxColumn.Index) { // 更新你的数据源,确保只有一行的复选框为选中状态 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值