如何检测DataGridView CheckBox事件的变化?

时间:2012-08-07 09:59:37

标签: c# winforms datagridview

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

  1. 单击CheckBox但在其检查状态发生变化之前触发,或
  2. 仅在CheckBox失去焦点时触发
  3. 我似乎无法找到在检查状态发生变化后立即触发的事件。


    修改

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

20 个答案:

答案 0 :(得分:78)

要处理DatGridView CheckedChanged事件,您必须首先触发CellContentClick(其中没有CheckBox当前状态!)然后调用{{ 1}}。这将反过来触发您可以用来完成工作的CommitEdit事件。 这是微软的疏忽。做一些像下面这样的事情......

CellValueChanged

我希望这会有所帮助。

P.S。查看此文章https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx

答案 1 :(得分:77)

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

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

  

“原因是OnCellvalueChanged事件在DataGridView认为你已经完成编辑之前不会触发。这会使TextBox专栏感觉到,因为OnCellvalueChanged不会为每次击键触发[bother],但它不会对于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();
    }
}

答案 2 :(得分:7)

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

答案 3 :(得分: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.....
    }

答案 4 :(得分:4)

以下是一些代码:

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

答案 5 :(得分:4)

关注Killercam'answer,我的代码

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
            }
        }
    }

答案 6 :(得分: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

关于此的最好的事情之一是不需要多个事件。

答案 7 :(得分:2)

所有关于编辑单元格的问题,即单元格实际上没有编辑的问题,因此您需要保存单元格或行的更改以在单击检查时获取事件框,以便您可以使用此功能:

datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)

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

答案 8 :(得分: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;
        }
    }
}

答案 9 :(得分:1)

对我有用的是CurrentCellDirtyStateChangeddatagridView1.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();
}

答案 10 :(得分: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;
        }
    }
}

答案 11 :(得分:0)

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

答案 12 :(得分:0)

我找到了一个更简单的答案来解决这个问题。我只是使用反向逻辑。代码在VB中,但与C#没什么不同。

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

    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

关于此的最好的事情之一是不需要多个事件。

答案 13 :(得分: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);
    }

}

答案 14 :(得分:0)

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

以下代码适用于我:

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

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

答案 15 :(得分:0)

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

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.

}

答案 16 :(得分:0)

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

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

严重的是,这就是您所需要的。

答案 17 :(得分: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
   }
}  

答案 18 :(得分: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();
                }
            }
        }

答案 19 :(得分:0)

我发现的最好方法(也不使用多个事件)是处理 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
        }
    }