2

I have a (.NET 3.5) winform with a datagridview on which I added an event on checkboxes in the gridview like this. That post doesn't take into account that people can also use spacebar to toggle the checkbox, and because there is no CellKeyUp event like there is a CellMouseUp event, I enabled KeyPreview on the form and added this code to prevent toggling with the spacebar:

private void BulkOrderAddressDifferencesForm_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Space)
    {
        e.Handled = true;
        e.SuppressKeyPress = true;
    }
}

That works mostly, but there is a scenario in which the event is still handled, even though the debugger shows e.Handled is set to true.

Form with controls

If I click on a checkbox, then 1, then 2, I can toggle the checkbox with the space bar again. I have no idea why this happens, nor do I know how to fix it.

Community
  • 1
  • 1
Halfgaar
  • 732
  • 2
  • 7
  • 32

3 Answers3

0

How about the DataGridView.EditMode Property which

Gets or sets a value indicating how to begin editing a cell.

where

The default is EditOnKeystrokeOrF2.

and

All DataGridViewEditMode values except for EditProgrammatically allow a user to double-click a cell to begin editing it.

You have several options to choose from the DataGridViewEditMode Enumeration

  • EditOnEnter - Editing begins when the cell receives focus. This mode is useful when pressing the TAB key to enter values across a row, or when pressing the ENTER key to enter values down a column.

  • EditOnF2 - Editing begins when F2 is pressed while the cell has focus. This mode places the selection point at the end of the cell contents.

  • EditOnKeystroke - Editing begins when any alphanumeric key is pressed while the cell has focus.

  • EditOnKeystrokeOrF2 - Editing begins when any alphanumeric key or F2 is pressed while the cell has focus.

  • EditProgrammatically - Editing begins only when the BeginEdit method is called.


Update for DataGridViewCheckBoxCell:

It turns out that the DataGridViewEditMode does not work for the DataGridViewCheckBoxColumn.

In this case you can create your own DataGridViewCheckBoxColumn & DataGridViewCheckBoxCell. This allows you to override the cell's OnKeyUp event handler and reset the EditingCellFormattedValue if Space was pressed.

public class MyCheckBoxColumn : DataGridViewCheckBoxColumn
{
    public MyCheckBoxColumn()
    {
        CellTemplate = new MyCheckBoxCell();
    }
}

public class MyCheckBoxCell : DataGridViewCheckBoxCell
{
    protected override void OnKeyUp(KeyEventArgs e, int rowIndex)
    {
        if (e.KeyCode == Keys.Space)
        {
            e.Handled = true;
            if (EditingCellValueChanged)
            {
                // Reset the value.
                EditingCellFormattedValue = !(bool)EditingCellFormattedValue;
            }
        }
        else
        {
            base.OnKeyUp(e, rowIndex);
        }
    }
}

After you rebuild your project the new column should appear in the designer:

enter image description here

t3chb0t
  • 16,340
  • 13
  • 78
  • 118
  • The only thing I can seem to accomplish with that property, is preventing any kind of editing, with `EditProgrammatically`. Other than that, the behavior is the same. – Halfgaar Jan 09 '15 at 12:06
  • I've updated my answer. You can try a custom cell. I've tested it and it worked for me. – t3chb0t Jan 09 '15 at 13:14
0

You can override Form's ProcessCmdKey method:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == Keys.Space && checkBox1.Focused)
    {
        //instead of checkBox1.Focused condition, you check if your DataGridView contains focus and active cell is of checkBox type 
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}
Artem Kachanovskyi
  • 1,839
  • 2
  • 18
  • 27
0

If the goal is to always react immediately when the check is changed, rather than preventing the use of the spacebar (Unless I'm mistaken, the problem is that the cellmouseup approach doesn't include (un)checking with space, rather than the goal is that space shouldn't be used at all? ), you could use the celldirtychanged approach instead of cellmouseup to catch both

//grid.CurrentCellDirtyStateChanged += grid_CurrentCellDirtyStateChanged;

        void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            if (grid.IsCurrentCellDirty)
            {
                var cell = grid.CurrentCell;
                if (cell is DataGridViewCheckBoxCell)
                {
                    grid.EndEdit();
                    //you could catch the cellvaluechanged event (or a bound listchanged event), or handle the change immediately here, e.g.:
                    //Console.WriteLine("{0} value changed to {1}", cell.OwningColumn.HeaderText, cell.Value);
                }
            }
        }
Me.Name
  • 12,259
  • 3
  • 31
  • 48