35

I have a grid view that has a check box column, and I want to trigger a drawing event as soon as the value of the cell is toggled. I tried the ValueChaged and the CellEndEdit and BeginEdit, and chose the selection mode as CellSelect. As for the the first 2 events, the event was triggered upon the finishing of the edit mode, like moving out of the current cell, or going back and forth. It's just a weird behavior.

Is there anything that triggers the event on the grid view as soon as the cell value is changed?

mustafabar
  • 2,317
  • 6
  • 31
  • 47

15 Answers15

35

I use the CellContentClick event, which makes sure the user clicked the checkbox. It DOES fire multiple times even if the user stays in the same cell. The one issue is that the Value does not get updated, and always returns "false" for unchecked. The trick is to use the .EditedFormattedValue property of the cell instead of the Value property. The EditedFormattedValue will track with the check mark and is what one wishes the Value had in it when the CellContentClick is fired.

No need for a timer, no need for any fancy stuff, just use CellContentClick event and inspect the EditedFormattedValue to tell what state the checkbox is going into / just went into. If EditedFormattedValue = true, the checkbox is getting checked.

Christo
  • 8,729
  • 2
  • 22
  • 16
24

A colleague of mine recommends trapping the CurrentCellDirtyStateChanged event. See http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged.aspx.

user120381
  • 256
  • 2
  • 3
  • 2
    Combine that with the datagridview.EndEdit() and the bound data is updated – Brad Jun 06 '11 at 14:00
  • 2
    for me this is the right event. combined with a DataGridViewName.EndEdit() . thx for the solution – skofgar Aug 17 '11 at 13:11
  • I applied this code. But the value of the table will only update when I made extra movements (e.g. scroll the gridview, click cells, resize column, or any other movements). Please tell me what's going on? – ThEpRoGrAmMiNgNoOb Apr 30 '15 at 03:19
21

Another way is to handle the CellContentClick event (which doesn't give you the current value in the cell's Value property), call grid.CommitEdit(DataGridViewDataErrorContexts.Commit) to update the value which in turn will fire CellValueChanged where you can then get the actual (i.e. correct) DataGridViewCheckBoxColumn value.

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
}

Target .NET framework: 2.0

Stuart
  • 583
  • 5
  • 9
  • I applied this code. But the cellValueChanged event will only be executed when I make extra movements (e.g. scroll the gridview, click cells, resize column, or any other movements). Please tell me what's going on? – ThEpRoGrAmMiNgNoOb Apr 30 '15 at 06:42
5

Small update.... Make sure you use EditedFormattedValue instead of value as I tried value but it never give right status that is checked/unchecked most of the site still use value but as used in latest c# 2010 express below is one way to access..

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

Also _CellValueChanged event suggested or used by few must be usable for some cases but if you are looking for every check/uncheck of cell make sure you use _CellContentClick else per my notice I see not every time _CellValueChanged is fired.. that is if the same checkbox is clicked over & over again it does not fire _CellValueChanged but if you click alternately for example you have two chekbox & click one after other _CellValueChanged event will be fired but usually if looking for event to fire everytime the any cell is check/uncheck _CellValueChanged is not fired.

Ali Lotfi
  • 856
  • 3
  • 18
  • 40
user593029
  • 511
  • 7
  • 18
4

I had the same issue, but came up with a different solution:

If you make the column or the whole grid "Read Only" so that when the user clicks the checkbox it doesn't change value.

Fortunately, the DataGridView.CellClick event is still fired. In my case I do the following in the cellClick event:

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

But you could check the column name if you have more than one checkbox column.

I then do all the modification / saving of the dataset myself.

Ali Lotfi
  • 856
  • 3
  • 18
  • 40
James
  • 41
  • 1
4

Try hooking into the CellContentClick event. The DataGridViewCellEventArgs will have a ColumnIndex and a RowIndex so you can know if a ChecboxCell was in fact clicked. The good thing about this event is that it will only fire if the actual checkbox itself was clicked. If you click on the white area of the cell around the checkbox, it won't fire. This way, you're pretty much guaranteed that the checkbox value was changed when this event fires. You can then call Invalidate() to trigger your drawing event, as well as a call to EndEdit() to trigger the end of the row's editing if you need that.

BFree
  • 102,548
  • 21
  • 159
  • 201
  • but still the cell has to be deselected for this event to be triggered. So it you stay in the same cell and you click it for more than one time, the event wont be triggered – mustafabar May 31 '09 at 14:02
4

I finally implemented it this way

  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();
    }
mustafabar
  • 2,317
  • 6
  • 31
  • 47
1

"EditingControlShowing" event doesn't fire on checkbox value change. Because display style of the checkbox cell doesn't not change.

The workaround i have used is as below. (I have used CellContentClick event)

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

The above has worked for me. Please let me know if need more help.

Yamanappa
  • 119
  • 1
  • 2
1

I found a simple solution.

Just change the cell focus after click on cell.

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

    }
}

Don't forget to check if the column of your (ckeckbox + 1) index exist.

1

Every one of the CellClick and CellMouseClick answers is wrong, because you can change the value of the cell with the keyboard and the event will not fire. Additionally, CurrentCellDirtyStateChanged only fires once, which means if you check/uncheck the same box multiple times, you will only get one event. Combining a few of the answers above gives the following simple solution:

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.
}
Eric Lindsey
  • 954
  • 8
  • 19
0

Working with an unbound control (ie I manage the content programmatically), without the EndEdit() it only called the CurrentCellDirtyStateChanged once and then never again; but I found that with the EndEdit() CurrentCellDirtyStateChanged was called twice (the second probably caused by the EndEdit() but I didn't check), so I did the following, which worked best for me:

    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;
    }
James Carlyle-Clarke
  • 830
  • 1
  • 12
  • 19
0

Using the .EditedFormattedValue property solves the problem

To be notified each time a checkbox in a cell toggles a value when clicked, you can use the CellContentClick event and access the preliminary cell value .EditedFormattedValue.

As the event is fired the .EditedFormattedValue is not yet applied visually to the checkbox and not yet committed to the .Value property.

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
   var checkbox = dataGridView1.CurrentCell as DataGridViewCheckBoxCell;

   bool isChecked = (bool)checkbox.EditedFormattedValue;

}

The event fires on each Click and the .EditedFormattedValue toggles

flodis
  • 1,123
  • 13
  • 9
0

I found a combination of the first two answers gave me what I needed. I used the CurrentCellDirtyStateChanged event and inspected the 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;
        }
     }
}
Mike Pollitt
  • 1,817
  • 16
  • 13
0

Use this code, when you want to use the checkedChanged event in DataGrid View:

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

Here, grdBill = DataGridView1, gCheck = CheckBox in GridView(First Column), gBillNumber = TextBox in Grid (Second column).

So, when we want to fire checkchanged event for each click, first do the CellContentClick it will get fire when user clicked the Text box, then it will move the current cell to next column, so the CellEndEdit column will get fire, it will check the whether the checkbox is checked and add the "gBillNumber" in list box (in function calcBill).

Scott
  • 21,211
  • 8
  • 65
  • 72
Jegan
  • 1
-1

cellEndEditTimer.Start();

this line makes the datagridview update the list of checked boxes

Thank you.

Leandro
  • 15
  • 1
  • This answer requires additional components to be added to the form and does not work on its own. To make this a complete answer you need to inform users they need to add a Timer to the form and you should also provide the code for the Timer's `_Tick` event. – Eric Lindsey May 04 '19 at 06:15