winformsdatagridviewevent-handlingdatagridviewcheckboxcell

How to get the last click event on DataGridViewCheckBoxCell


I'm using a DataGridViewCheckBoxColumn inside a DataGridView in a WinForm panel.
When a checkbox is clicked, I need to compute things that might change a Control state outside the DataGridView.

To do so, I have to handle the CellContentClick event because I need to compute only when a checkbox value is actually changed.

Grid.CellContentClick += Grid_CellContentClick

private void Grid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;
    dgv.EndEdit();

    // Compute stuff
}

However CellContentClick doesn't always fire, while the internal event that does change the DataGridViewCheckboxCell checked state is.
Most importantly, fast successive clicks on a checkbox do not fire CellContentClick, only the first is catched until the user stops clicking.

As a result I end up in an invalid state where the control outside the DataGridView doesn't display as intended because the computation doesn't use the checkboxes final values.
I've tried to debounce the event and creating a pseudo-lock using MouseDown and the grid ReadOnly property, with no success.

Is there a way to catch only the last event of a series of clicks? Is there a better way to do this?


Solution

  • Thank you @Jimi and @JohnG for your insights, it helped me solving this issue.

    I could not make it work using CellValueChanged and CellContentClick, even with async and await Task.Delay(...) as it did not fire correctly and triggered inter-thread exceptions in my computation afterwards.
    It might just have been me though, but I wasn't very fond of using Threading in this context anyway.

    I hadn't considered using CellValueChanged and noticed that it wouldn't trigger for a DataGridViewCheckBoxCell when clicked, so I ended up reading this thread and the solution is actually quite simple.

    Grid.CurrentCellDirtyStateChanged += Grid_CurrentCellDirtyStateChanged;
    Grid.CellValueChanged += Grid_CellValueChanged;
    
    private void Grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        if (Grid.IsCurrentCellDirty)
        {
            Grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }
    }
    private void Grid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        DataGridViewCheckBoxCell cell = (DataGridViewCheckBoxCell)Grid[e.ColumnIndex, e.RowIndex];
    
        // Compute stuff
    }
    

    This code is executed each time a grid checkbox is clicked on, and has a far better logic since it relies on a direct value change.
    However it means the computation takes place each time the value is changed.

    I believe one could debounce the computation in order to improve this solution, fortunately mine isn't too resource expensive so it runs smoothly and I don't need to take it that far.