105

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

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

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


编辑:

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

4

19 回答 19

118

要处理DatGridViewsCheckedChanged事件,您必须首先获得CellContentClickto 触发(它没有CheckBoxes 当前状态!)然后调用CommitEdit. 这将反过来触发CellValueChanged您可以用来完成工作的事件。这是微软的疏忽。做一些类似下面的事情......

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();
}

我希望这有帮助。

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

于 2012-08-07T10:42:28.083 回答
95

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

它使用数据网格的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();
    }
}
于 2013-02-21T20:44:20.780 回答
9

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();
    }
}
于 2014-10-06T22:18:00.850 回答
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);
    }
}
于 2012-12-12T10:54:31.963 回答
6

按照 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
            }
        }
    }
于 2013-12-24T10:01:13.320 回答
6

这也处理键盘激活。

    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.....
    }
于 2014-07-06T22:12:10.217 回答
2

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

datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)

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

于 2015-07-28T13:16:42.767 回答
2

对于这个问题,我找到了一个更简单的答案。我只是使用反向逻辑。代码在 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

最好的事情之一就是不需要多个事件。

于 2017-08-04T05:54:44.450 回答
2

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

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.

}
于 2019-07-16T14:51:46.253 回答
2

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

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

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

于 2020-07-12T17:57:14.847 回答
1

对我有用的是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();
}
于 2013-08-28T04:38:21.577 回答
1

代码将在 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;
        }
    }
}
于 2015-09-30T08:23:23.957 回答
1

在事件 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;
        }
    }
}
于 2018-02-22T10:26:42.523 回答
1

我发现的最好方法(也不使用多个事件)是处理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
        }
    }
于 2021-08-04T06:37:20.253 回答
0

要在使用 devexpress xtragrid 时执行此操作,必须按照此处所述处理相应存储库项的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 循环来遍历行。

于 2017-02-27T16:48:09.967 回答
0

在单元格值更改后移除焦点允许在 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);
    }

}
于 2017-09-27T03:14:03.397 回答
0

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

以下代码适用于我:

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

然后,您可以在CellValueChanged事件中插入您的代码。

于 2017-11-03T20:17:33.523 回答
0

我将 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
   }
}  
于 2020-12-10T09:46:29.383 回答
0

这对我有用

  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();
                }
            }
        }
于 2021-04-05T22:17:37.097 回答