在 DataGridView 中触发复选框值更改事件

Posted

技术标签:

【中文标题】在 DataGridView 中触发复选框值更改事件【英文标题】:Triggering a checkbox value changed event in DataGridView 【发布时间】:2010-10-30 05:50:12 【问题描述】:

我有一个带有复选框列的网格视图,我想在切换单元格的值后立即触发绘图事件。我尝试了 ValueChaged 和 CellEndEdit 和 BeginEdit,并选择了选择模式为 CellSelect。至于前两个事件,该事件是在编辑模式结束时触发的,比如移出当前单元格,或者来回移动。这只是一种奇怪的行为。

一旦单元格值更改,是否有任何东西会触发网格视图上的事件?

【问题讨论】:

【参考方案1】:

我使用 CellContentClick 事件,它确保用户点击了复选框。即使用户留在同一个单元格中,它也会触发多次。一个问题是 Value 没有得到更新,并且对于未选中总是返回“false”。诀窍是使用单元格的 .EditedFormattedValue 属性而不是 Value 属性。 EditedFormattedValue 将使用复选标记进行跟踪,并且是在触发 CellContentClick 时希望 Value 包含在其中的内容。

不需要计时器,不需要任何花哨的东西,只需使用 CellContentClick 事件并检查 EditedFormattedValue 来判断复选框正在进入/刚刚进入的状态。如果 EditedFormattedValue = true,则复选框被选中。

【讨论】:

【参考方案2】:

我的一位同事建议捕获 CurrentCellDirtyStateChanged 事件。见http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged.aspx。

【讨论】:

将其与 datagridview.EndEdit() 结合并更新绑定数据 对我来说这是正确的事件。结合 DataGridViewName.EndEdit() 。谢谢解决方案 我应用了这段代码。但是表格的值只会在我进行额外动作时更新(例如滚动网格视图、单击单元格、调整列大小或任何其他动作)。请告诉我发生了什么事?【参考方案3】:

另一种方法是处理 CellContentClick 事件(它不会为您提供单元格的 Value 属性中的当前值),调用 grid.CommitEdit(DataGridViewDataErrorContexts.Commit) 来更新值,这反过来会在您可以触发的地方触发 CellValueChanged然后获取实际的(即正确的)DataGridViewCheckBoxColumn 值。

private void grid_CellContentClick(object sender, DataGridViewCellEventArgs e)

   grid.CommitEdit(DataGridViewDataErrorContexts.Commit);


private void grid_CellValueChanged(object sender, DataGridViewCellEventArgs e)

    // do something with grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value

目标 .NET 框架:2.0

【讨论】:

我应用了这段代码。但是只有当我进行额外的动作(例如滚动网格视图、单击单元格、调整列大小或任何其他动作)时才会执行 cellValueChanged 事件。请告诉我发生了什么事?【参考方案4】:

尝试挂钩 CellContentClick 事件。 DataGridViewCellEventArgs 将有一个 ColumnIndex 和一个 RowIndex,因此您可以知道是否确实单击了 ChecboxCell。这个事件的好处是它只会在实际的复选框本身被点击时触发。如果单击复选框周围单元格的白色区域,它将不会触发。这样,您几乎可以保证在此事件触发时复选框值已更改。然后,您可以调用 Invalidate() 来触发绘图事件,也可以调用 EndEdit() 来触发行编辑的结束(如果需要)。

【讨论】:

但仍必须取消选择单元格才能触发此事件。因此,如果您停留在同一个单元格中并且单击它不止一次,则不会触发该事件【参考方案5】:

我终于这样实现了

  private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
    

        if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
        
            if (dataGridView1[e.ColumnIndex, e.RowIndex].GetContentBounds(e.RowIndex).Contains(e.Location))
            
                cellEndEditTimer.Start();
            
        

    

    private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
     /*place your code here*/


    private void cellEndEditTimer_Tick(object sender, EventArgs e)
    
        dataGridView1.EndEdit();
        cellEndEditTimer.Stop();
    

【讨论】:

【参考方案6】:

我遇到了同样的问题,但想出了一个不同的解决方案:

如果您将列或整个网格设置为“只读”,这样当用户单击复选框时它不会更改值。

幸运的是,DataGridView.CellClick 事件仍然被触发。 就我而言,我在 cellClick 事件中执行以下操作:

if (jM_jobTasksDataGridView.Columns[e.ColumnIndex].CellType.Name == "DataGridViewCheckBoxCell")

但如果您有多个复选框列,则可以检查列名。

然后我自己进行数据集的所有修改/保存。

【讨论】:

【参考方案7】:

小更新....确保您使用EditedFormattedValue 而不是value,因为我尝试过value,但它永远不会给出正确的状态,即已选中/未选中大多数站点仍然使用value,但已使用在最新的 c# 2010 express 下面是一种访问方式..

grdJobDetails.Rows[e.RowIndex].Cells[0].EditedFormattedValue

此外,少数人建议或使用的_CellValueChanged 事件必须在某些情况下可用,但如果您正在寻找对单元格的每次检查/取消检查,请确保使用_CellContentClick,否则根据我的通知,我并非每次都看到_CellValueChanged被触发..如果相同的复选框被反复点击,它不会触发_CellValueChanged,但如果你交替点击,例如你有两个复选框并在另一个_CellValueChanged事件之后点击一个,但通常如果寻找每次选中/取消选中任何单元格时都会触发事件 _CellValueChanged 不会触发。

【讨论】:

【参考方案8】:

“EditingControlShowing”事件不会在复选框值更改时触发。因为复选框单元格的显示样式没有改变。

我使用的解决方法如下。 (我用过 CellContentClick 事件)

    private void gGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
    
        if (string.Compare(gGridView1.CurrentCell.OwningColumn.Name, "CheckBoxColumn") == 0)
        
            bool checkBoxStatus = Convert.ToBoolean(gGridView1.CurrentCell.EditedFormattedValue);
            //checkBoxStatus gives you whether checkbox cell value of selected row for the
            //"CheckBoxColumn" column value is checked or not. 
            if(checkBoxStatus)
            
                //write your code
            
            else
            
               //write your code
            
        
    

以上对我有用。如果需要更多帮助,请告诉我。

【讨论】:

【参考方案9】:

我找到了一个简单的解决方案。

单击单元格后只需更改单元格焦点。

private void DGV_CellContentClick(object sender, DataGridViewCellEventArgs e)

    if (e.ColumnIndex == "Here checkbox column id or name") 
        DGV.Item(e.ColumnIndex, e.RowIndex + 1).Selected = true;
        //Here your code

    

不要忘记检查 (ckeckbox + 1) 索引的列是否存在。

【讨论】:

【参考方案10】:

CellClickCellMouseClick 的每个答案都是错误的,因为您可以使用键盘更改单元格的值,并且不会触发事件。此外,CurrentCellDirtyStateChanged 只会触发一次,这意味着如果您多次选中/取消选中同一个框,您只会得到一个事件。结合上面的几个答案给出以下简单的解决方案:

private void dgvList_CurrentCellDirtyStateChanged(object sender, EventArgs e)

    if (dgvList.CurrentCell is DataGridViewCheckBoxCell)
        dgvList.CommitEdit(DataGridViewDataErrorContexts.Commit);


private void dgvList_CellValueChanged(object sender, DataGridViewCellEventArgs e)

    // Now this will fire immediately when a check box cell is changed,
    // regardless of whether the user uses the mouse, keyboard, or touchscreen.
    //
    // Value property is up to date, you DO NOT need EditedFormattedValue here.

【讨论】:

【参考方案11】:

cellEndEditTimer.Start();

这一行使 datagridview 更新复选框列表

谢谢。

【讨论】:

此答案需要将其他组件添加到表单中,并且不能单独使用。为了使这个回答完整,您需要通知用户他们需要在表单中添加一个计时器,并且您还应该提供计时器的_Tick 事件的代码。【参考方案12】:

我发现前两个答案的组合满足了我的需求。我使用了 CurrentCellDirtyStateChanged 事件并检查了 EditedFormattedValue。

private void dgv_CurrentCellDirtyStateChanged(object sender, EventArgs e)

   DataGridView dgv = (DataGridView)sender;
   DataGridViewCell cell = dgv.CurrentCell;
   if (cell.RowIndex >= 0 && cell.ColumnIndex == 3) // My checkbox column
     
        // If checkbox checked, copy value from col 1 to col 2
        if (dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue != null && dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue.Equals(true))
        
           dgv.Rows[cell.RowIndex].Cells[1].Value = dgv.Rows[cell.RowIndex].Cells[2].Value;
        
     

【讨论】:

【参考方案13】:

当您想在 DataGrid 视图中使用 checkedChanged 事件时,请使用此代码:

private void grdBill_CellContentClick(object sender, DataGridViewCellEventArgs e)

    grdBill.CurrentCell =  grdBill.Rows[grdBill.CurrentRow.Index].Cells["gBillNumber"];


private void grdBill_CellEndEdit(object sender, DataGridViewCellEventArgs e)

    calcBill();


private void calcBill()

    listBox1.Items.Clear();
    for (int i = 0; i < grdBill.Rows.Count - 1; i++)
    
        if (Convert.ToBoolean(grdBill.Rows[i].Cells["gCheck"].Value) == true)
        
            listBox1.Items.Add(grdBill.Rows[i].Cells["gBillNumber"].Value.ToString());
        
    

这里,grdBill = DataGridView1, gCheck = CheckBox in GridView(First Column), gBillNumber = TextBox 在网格(第二列)中。

所以,当我们想要为每次点击触发 checkchanged 事件时,首先执行 CellContentClick,当用户点击文本框时它会触发,然后它将当前单元格移动到下一列,因此 CellEndEdit 列会触发,它将检查复选框是否被选中并在列表框中添加“gBillNumber”(在函数calcBill中)。

【讨论】:

【参考方案14】:

使用未绑定的控件(即我以编程方式管理内容),没有 EndEdit() 它只调用 CurrentCellDirtyStateChanged 一次,然后再也不会;但我发现使用 EndEdit() CurrentCellDirtyStateChanged 被调用了两次(第二次可能是由 EndEdit() 引起的,但我没有检查),所以我做了以下,这对我来说效果最好:

    bool myGridView_DoCheck = false;
    private void myGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    
        if (!myGridView_DoCheck)
        
            myGridView_DoCheck = true;
            myGridView.EndEdit();
            // do something here
        
        else
            myGridView_DoCheck = false;
    

【讨论】:

【参考方案15】:

使用 .EditedFormattedValue 属性可以解决问题

要在每次单击单元格中的复选框切换值时收到通知,您可以使用 CellContentClick 事件并访问初始单元格值 .EditedFormattedValue

在触发事件时,.EditedFormattedValue 尚未在视觉上应用于复选框,也尚未提交给 .Value 属性。

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)

   var checkbox = dataGridView1.CurrentCell as DataGridViewCheckBoxCell;

   bool isChecked = (bool)checkbox.EditedFormattedValue;


事件在每次点击时触发,.EditedFormattedValue 切换

【讨论】:

以上是关于在 DataGridView 中触发复选框值更改事件的主要内容,如果未能解决你的问题,请参考以下文章

将包含文本值“true”文本的 datagridview 单元格类型更改为复选框

选中复选框后如何更改datagridview中的行颜色

更改复选框值而不触发 onCheckChanged

winform中datagridview怎么添加行之后将焦点选中在新添加的行?

如何将数据源绑定到 datagridview 组合框和复选框

Datagridview 在更改列组合框值时执行代码