如何检测 DataGridView CheckBox 事件变化?

Posted

技术标签:

【中文标题】如何检测 DataGridView CheckBox 事件变化?【英文标题】:How to detect DataGridView CheckBox event change? 【发布时间】:2012-08-07 09:59:36 【问题描述】:

我有一个 winforms 应用程序,并希望在选中/取消选中嵌入在 DataGridView 控件中的复选框时触发一些代码。我尝试过的每个事件

    在单击 CheckBox 但在其选中状态更改之前触发,或 仅在 CheckBox 失去焦点时触发

我似乎找不到在选中状态更改后立即触发的事件。


编辑:

我想要实现的是,当一个DataGridView 中的CheckBox 的选中状态发生变化时,另外两个DataGridViews 中的数据也会发生变化。然而,我使用过的所有事件,其他网格中的数据仅在第一个 DataGridView 中的 CheckBox 失去焦点后发生变化。

【问题讨论】:

你检查CurrentCellDirtyStateChanged事件了吗? 仍然只在用户“离开”单元格时执行。 这是 MSDN 上的文章:msdn.microsoft.com/en-us/library/… 与 Killercam 的回答类似但略有不同 您可能需要考虑将ListViewlistView.View = System.Windows.Forms.View.Details; listView.CheckBoxes = true; 一起使用,然后它会显示为一个表格,开头带有复选框。在那里,您可以使用 listView.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(methodname); 轻松解决 Checkbox 选中事件 【参考方案1】:

要处理DatGridViews CheckedChanged 事件,您必须首先触发CellContentClick(它没有CheckBoxes 当前状态!)然后调用CommitEdit。这将反过来触发CellValueChanged 事件,您可以使用该事件来完成您的工作。 这是 Microsoft 的疏忽。执行以下操作...

private void dataGridViewSites_CellContentClick(object sender, 
    DataGridViewCellEventArgs e)

    dataGridViewSites.CommitEdit(DataGridViewDataErrorContexts.Commit);


/// <summary>
/// Works with the above.
/// </summary>
private void dataGridViewSites_CellValueChanged(object sender, 
    DataGridViewCellEventArgs e)

    UpdateDataGridViewSite();

我希望这会有所帮助。

附:查看这篇文章https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx

【讨论】:

这是一个很好的解决方案,但如果用户点击几次就不起作用,在***.com/questions/11843488/…下方发布了替代方案 我也强烈建议不要将此解决方案用于双击问题。需要调用EndEdit()函数……从@56ka找到链接,点击文章链接! 我并没有在这个解决方案上花费很长时间,如果@56ka 的解决方案更好,那就太好了。但是,我不确定双击DataGridViewCheckBox 有什么大惊小怪的。这不是 WPF,双击控件不会破坏任何数据绑定,它是 WinForms。双击可能不会在视觉上更新控件,但它不会破坏任何东西,在这种情况下,也许下面的解决方案是更好的解决方案。谢谢。 如果您将相同的代码从 CellContentClick 添加到 CellContentDoubleClick 中,这将非常有效。 CellMouseUp 即使选中了单元格但未单击复选框,也会触发 - 这是不希望的行为。 @torpidprey 或者只是为CellContentDoubleClick 设置CellContentClick 事件处理程序而不是复制,让这两个处理程序触发一个处理程序。您的解决方案修复了我的 winform 应用程序中的双击问题。【参考方案2】:

我发现@Killercam 的解决方案可以工作,但如果用户双击速度太快,就会有点狡猾。不确定其他人是否也发现了这种情况。我找到了另一个解决方案here。

它使用数据网格的CellValueChangedCellMouseUp。长虹解释说

“原因是 OnCellvalueChanged 事件在 DataGridView 认为您已完成编辑之前不会触发。这对于 TextBox 列是有意义的,因为 OnCellvalueChanged 不会 [打扰] 为每个按键触发触发,但它不会对于 CheckBox 来说 [有意义]。”

这是他的例子:

private void myDataGrid_OnCellValueChanged(object sender, DataGridViewCellEventArgs e)

    if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
    
        // Handle checkbox state change here
    

当它被点击时告诉复选框它完成编辑的代码,而不是等到用户离开该字段:

private void myDataGrid_OnCellMouseUp(object sender,DataGridViewCellMouseEventArgs e)

    // End of edition on each click on column of checkbox
    if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
    
        myDataGrid.EndEdit();
    

编辑:DoubleClick 事件与 MouseUp 事件分开处理。如果检测到 DoubleClick 事件,应用程序将完全忽略第一个 MouseUp 事件。除了 MouseUp 事件之外,还需要将这个逻辑添加到 CellDoubleClick 事件中:

private void myDataGrid_OnCellDoubleClick(object sender,DataGridViewCellEventArgs e)

    // End of edition on each click on column of checkbox
    if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
    
        myDataGrid.EndEdit();
    

【讨论】:

我遇到了响应者提到的双击问题,这个问题比第一个解决方案更有效。 我也遇到了双击问题,这个解决方案解决了。 点击“这里”按钮并查看文章。我在双击时遇到了同样的问题。 如果用空格键切换开关会怎样? 为了“修复”空格键问题,我在表单上将KeyPreview 设置为true,当e.KeyCode == Keys.Space 时,设置e.Handled = true。换句话说,我只是禁用了键盘编辑。【参考方案3】:

jsturtevants 的解决方案效果很好。但是,我选择在 EndEdit 事件中进行处理。我更喜欢这种方法(在我的应用程序中),因为与 CellValueChanged 事件不同,EndEdit 事件不会在您填充网格时触发。

这是我的代码(其中一部分是从 jsturtevant 偷来的:

private void gridCategories_CellEndEdit(object sender, DataGridViewCellEventArgs e)

    if (e.ColumnIndex == gridCategories.Columns["AddCategory"].Index)
    
        //do some stuff
    




private void gridCategories_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)

    if (e.ColumnIndex == gridCategories.Columns["AddCategory"].Index)
    
        gridCategories.EndEdit();
    

【讨论】:

好答案,但最好使用CellContentClick 而不是CellMouseUp,因为后者将在用户单击单元格内的任何位置时调用,而前者仅在单击复选框时调用.【参考方案4】:

按照 Killercam 的回答,我的代码

private void dgvProducts_CellContentClick(object sender, DataGridViewCellEventArgs e)
    
        dgvProducts.CommitEdit(DataGridViewDataErrorContexts.Commit);
    

和:

private void dgvProducts_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    
        if (dgvProducts.DataSource != null)
        
            if (dgvProducts.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "True")
            
                //do something
            
            else
            
               //do something
            
        
    

【讨论】:

【参考方案5】:

这也处理键盘激活。

    private void dgvApps_CellContentClick(object sender, DataGridViewCellEventArgs e)
    
        if(dgvApps.CurrentCell.GetType() == typeof(DataGridViewCheckBoxCell))
        
            if (dgvApps.CurrentCell.IsInEditMode)
            
                if (dgvApps.IsCurrentCellDirty)
                
                    dgvApps.EndEdit();
                
            
        
    


    private void dgvApps_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    
          // handle value changed.....
    

【讨论】:

【参考方案6】:

这里有一些代码:

private void dgvStandingOrder_CellContentClick(object sender, DataGridViewCellEventArgs e)

    if (dgvStandingOrder.Columns[e.ColumnIndex].Name == "IsSelected" && dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell)
    
        bool isChecked = (bool)dgvStandingOrder[e.ColumnIndex, e.RowIndex].EditedFormattedValue;
        if (isChecked == false)
        
            dgvStandingOrder.Rows[e.RowIndex].Cells["Status"].Value = "";
        
        dgvStandingOrder.EndEdit();
    


private void dgvStandingOrder_CellEndEdit(object sender, DataGridViewCellEventArgs e)


    dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit);


private void dgvStandingOrder_CurrentCellDirtyStateChanged(object sender, EventArgs e)

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

【讨论】:

这个答案包含正确的答案,它处理鼠标和键盘交互,以及重复交互而不离开单元格。但只需要最后一个处理程序——从CurrentCellDirtyStateChanged 调用CommitEdit 是整个解决方案。【参考方案7】:

都是编辑单元格,问题是单元格实际上没有编辑,所以你需要保存单元格或行的变化来获取点击复选框时的事件,这样你就可以使用功能:

datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)

有了这个,你甚至可以在不同的事件中使用它。

【讨论】:

【参考方案8】:

我找到了这个问题的更简单的答案。我只是使用反向逻辑。代码在 VB 中,但与 C# 没有太大区别。

 Private Sub DataGridView1_CellContentClick(sender As Object, e As 
 DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick

    Dim _ColumnIndex As Integer = e.ColumnIndex
    Dim _RowIndex As Integer = e.RowIndex

    'Uses reverse logic for current cell because checkbox checked occures 
     'after click
    'If you know current state is False then logic dictates that a click 
     'event will set it true
    'With these 2 check boxes only one can be true while both can be off

    If DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False And 
       DataGridView1.Rows(_RowIndex).Cells("Column3").Value = True Then
        DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False
    End If

    If DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False And 
    DataGridView1.Rows(_RowIndex).Cells("Column2").Value = True Then
        DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False
    End If


End Sub

最好的一点是不需要多个事件。

【讨论】:

【参考方案9】:

我从这里尝试了一些答案,但我总是遇到某种问题(例如双击或使用键盘)。所以,我将其中一些结合起来,得到了一致的行为(它并不完美,但可以正常工作)。

void gridView_CellContentClick(object sender, DataGridViewCellEventArgs e) 
  if(gridView.CurrentCell.GetType() != typeof(DataGridViewCheckBoxCell))
    return;
  if(!gridView.CurrentCell.IsInEditMode)
    return;
  if(!gridView.IsCurrentCellDirty)
    return;
  gridView.EndEdit();


void gridView_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e) 
  if(e.ColumnIndex == gridView.Columns["cFlag"].Index && e.RowIndex >= 0)
    gridView.EndEdit();


void gridView_CellValueChanged(object sender, DataGridViewCellEventArgs e) 
  if(e.ColumnIndex != gridView.Columns["cFlag"].Index || e.RowIndex < 0)
    return;

  // Do your stuff here.


【讨论】:

【参考方案10】:

Ben Voigt 在上面的评论回复中找到了最佳解决方案:

private void dgvStandingOrder_CurrentCellDirtyStateChanged(object sender, EventArgs e)

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

说真的,这就是你所需要的。

【讨论】:

【参考方案11】:

对我有用的是CurrentCellDirtyStateChanged 结合datagridView1.EndEdit()

private void dataGridView1_CurrentCellDirtyStateChanged( object sender, EventArgs e ) 
    if ( dataGridView1.CurrentCell is DataGridViewCheckBoxCell ) 
        DataGridViewCheckBoxCell cb = (DataGridViewCheckBoxCell)dataGridView1.CurrentCell;
        if ( (byte)cb.Value == 1 ) 
            dataGridView1.CurrentRow.Cells["time_loadedCol"].Value = DateTime.Now.ToString();
        
    
    dataGridView1.EndEdit();

【讨论】:

【参考方案12】:

代码将在 DataGridView 中循环并检查 CheckBox 列是否被选中

private void dgv1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)

    if (e.ColumnIndex == 0 && e.RowIndex > -1)
    
        dgv1.CommitEdit(DataGridViewDataErrorContexts.Commit);
        var i = 0;
        foreach (DataGridViewRow row in dgv1.Rows)
        
            if (Convert.ToBoolean(row.Cells[0].Value))
            
                i++;
            
        

        //Enable Button1 if Checkbox is Checked
        if (i > 0)
        
            Button1.Enabled = true;
        
        else
        
            Button1.Enabled = false;
        
    

【讨论】:

【参考方案13】:

在 CellContentClick 事件中你可以使用这个策略:

private void myDataGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
    
    if (e.ColumnIndex == 2)//set your checkbox column index instead of 2
       //When you check
        if (Convert.ToBoolean(myDataGrid.Rows[e.RowIndex].Cells[2].EditedFormattedValue) == true)
        
            //EXAMPLE OF OTHER CODE
            myDataGrid.Rows[e.RowIndex].Cells[5].Value = DateTime.Now.ToShortDateString();

            //SET BY CODE THE CHECK BOX
            myDataGrid.Rows[e.RowIndex].Cells[2].Value = 1;
        
        else //When you decheck
        
            myDataGrid.Rows[e.RowIndex].Cells[5].Value = String.Empty;

            //SET BY CODE THE CHECK BOX
            myDataGrid.Rows[e.RowIndex].Cells[2].Value = 0;
        
    

【讨论】:

【参考方案14】:

我发现的最好方法(也不使用多个事件)是处理 CurrentCellDirtyStateChanged 事件。

private void dataGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    
        if (dataGridMatten.CurrentCell.OwningColumn == dataGridMatten.Columns["checkBoxColumn"] && dataGridMatten.IsCurrentCellDirty)
        
            dataGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);

            //your code goes here
        
    

【讨论】:

这对我来说是醒的【参考方案15】:

要在使用 devexpress xtragrid 时执行此操作,必须按照 here 的描述处理相应存储库项的 EditValueChanged 事件。调用 gridView1.PostEditor() 方法以确保已发布更改的值也很重要。这是一个实现:

        private void RepositoryItemCheckEdit1_EditValueChanged(object sender, System.EventArgs e)
        
            gridView3.PostEditor();

            var isNoneOfTheAboveChecked = false;

            for (int i = 0; i < gridView3.DataRowCount; i++)
            
                if ((bool) (gridView3.GetRowCellValue(i, "NoneOfTheAbove")) && (bool) (gridView3.GetRowCellValue(i, "Answer")))
                
                    isNoneOfTheAboveChecked = true;
                    break;
                
            

            if (isNoneOfTheAboveChecked)
            
                for (int i = 0; i < gridView3.DataRowCount; i++)
                
                    if (!((bool)(gridView3.GetRowCellValue(i, "NoneOfTheAbove"))))
                    
                        gridView3.SetRowCellValue(i, "Answer", false);
                    
                
            
        

请注意,由于 xtragrid 不提供枚举器,因此必须使用 for 循环来遍历行。

【讨论】:

【参考方案16】:

在单元格值更改后移除焦点允许在 DataGridView 中更新值。通过将 CurrentCell 设置为 null 来移除焦点。

private void DataGridView1OnCellValueChanged(object sender, DataGridViewCellEventArgs dataGridViewCellEventArgs)

    // Remove focus
    dataGridView1.CurrentCell = null;
    // Put in updates
    Update();


private void DataGridView1OnCurrentCellDirtyStateChanged(object sender, EventArgs eventArgs)

    if (dataGridView1.IsCurrentCellDirty)
    
        dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    


【讨论】:

【参考方案17】:

您可以在单击复选框后强制单元格提交值,然后捕获 CellValueChanged 事件。 CurrentCellDirtyStateChanged 在您单击复选框后立即触发。

以下代码适用于我:

private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    
        SendKeys.Send("tab");
    

然后您可以将代码插入到 CellValueChanged 事件中。

【讨论】:

【参考方案18】:

我将 DataGridView 与 VirtualMode=true 一起使用,只有这个选项对我有用 (当鼠标和空格键都在工作时,包括重复的空格键):

private void doublesGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)

   var data_grid = (DataGridView)sender;
      
   if (data_grid.CurrentCell.IsInEditMode && data_grid.IsCurrentCellDirty) 
      data_grid.EndEdit();            
   


private void doublesGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)

   if (e.ColumnIndex == CHECKED_COLUMN_NUM && e.RowIndex >= 0 && e.RowIndex < view_objects.Count)  // view_objects - pseudocode   
     view_objects[e.RowIndex].marked = !view_objects[e.RowIndex].marked;        // Invert the state of the displayed object
   
  

【讨论】:

【参考方案19】:

这对我有用

  private void employeeDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        
            if (e.ColumnIndex == employeeDataGridView.Columns["employeeStatusColumn"].Index)
            
                bool isChecked = (bool)employeeDataGridView.CurrentCell.Value;
                if (isChecked)
                
                    MessageBox.Show("Checked " + isChecked); //out true;
                
                else
                
                    MessageBox.Show("unChecked " + isChecked);
                
            

        

        private void employeeDataGridView_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
        
            if (employeeDataGridView.DataSource != null)
            
                if (e.ColumnIndex == employeeDataGridView.Columns["employeeStatusColumn"].Index && e.RowIndex != -1)
                
                    employeeDataGridView.EndEdit();
                
            
        

【讨论】:

rawaha 欢迎来到 Stack Overflow!如果您可以添加对您的代码如何工作的描述,并可能解释这与该线程上提供的其他解决方案有何不同或更好,这将很有帮助。

以上是关于如何检测 DataGridView CheckBox 事件变化?的主要内容,如果未能解决你的问题,请参考以下文章

C# DataGridView 检测全选按钮

RadGridView 检测 CellClick 事件按钮

单击datagridview中的复选框时启用按钮?

在Delphi中如何使用XpMenu这个控件??谢谢~!

禁用按下CTRL时选择的DataGridView行

C# winform datagridview如何计算统计