views:

944

answers:

4

I have a problem that I am not sure how to solve. I have a DataGridView (EditMode = EditProgrammatically). This grid has one checkbox column and one or more textbox columns. The functionality is as following (or should be at least):

  • When you click on a checkbox, the checkbox should be toggled
  • When a row (or many rows) are selected, and you press space, the checkboxes should be toggled.

I have these two event handlers:

    private void grid_CellClick(object sender, DataGridViewCellEventArgs e)
    {
        if (e.RowIndex >= 0 && e.ColumnIndex == useColumn.Index)
        {
            if (ModifierKeys != Keys.Shift && ModifierKeys != Keys.Control)
            {
                ToggleRows(grid.SelectedRows);
            }
        }
    }


    private void RowSelectorForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (grid.Focused && e.KeyCode == Keys.Space)
        {
            ToggleRows(grid.SelectedRows);
            e.Handled = true;  // Not sure if this is needed or even does anything
            e.SuppressKeyPress = true;  // Or this for that matter...
        }
    }

This almost works. The problem is when you press space and a checkbox cell is active. When a textbox cell is active, it works like it should. The problem is that when you press space and a checkbox cell is active, both events gets fired. Which means it first selects and then deselects (or the reverse). So the checkboxes end up being like they was. How can I prevent this?

I have thought about using a flag, but not sure where I can put it, since I can't really know if it was a double event or if it was just the user using space and then clicking with the mouse. So that can't really be used I think. Is there a different event I should use? Is there a way to see if the cell was clicked by mouse or by space? Is there a way to disable the automatic checkbox toggling when space is pressed? What can I do?


Note: Reason for RowSelectorForm_KeyDown and not just grid_KeyDown was that I was trying to use KeyPreview and then suppress the keypress if it was space and the grid was focused. But that SuppressKeyPress doesn't really seem to do anything at all =/ Maybe I've just misunderstood it...

A: 

Well, I didn't want to do it, but I have now fixed it with a timer... but if anyone knows how to do it properly, please let me know!!


Current solution:

private DateTime lastClick = DateTime.MinValue;

and in both events:

if (DateTime.Now - lastClick > TimeSpan.FromMilliseconds(400))
{
  lastClick = DateTime.Now;
  ToggleRows(grid.SelectedRows);
}
Svish
A: 

It has been a time since I worked with C#, but I assume that you can disconnect the grid_CellClick event handler before calling ToggleGrid in RowSelectorForm_KeyDown.

After the call, you can reconnect the event handler.

Also, there might be some way to supress the event from being fired in the first place. In some API's certain methods are specially provided that don't trigger any events.

Nailer
A: 

The frustrating problems are:

  1. .Handled doesn't prevent the check box from changing
  2. .SuppressKeyPress doesn't prevent the checkbox from changing
  3. If you DoubleClick on the checkbox, the first click fires the Click() event (toggling the checkbox) and the second click fires the DoubleClick() event (toggling the checkbox yet again).

However, the KeyDown event fires before any of the grid events. Perhaps setting a flag to indicate the spacebar was pressed or if the row was already selected, reset the value of the checkbox.

A: 

I used the following and it seemed to work well:

private Keys _ClickSource = 0;

private void dgv_CellClick(object sender, System.Windows.Forms.DataGridViewCellEventArgs e)
{
 if (_ClickSource == 0 || _ClickSource != Keys.Space)
 {
  dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = ! (System.Convert.ToBoolean(dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value));
 }

 _ClickSource = null;
}

private void dgv_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
 _ClickSource = e.KeyCode;
}
OneSource
Should `if (_ClickSource == 0 || _ClickSource != Keys.Space)` have been `if (_ClickSource == null || _ClickSource != Keys.Space)`?
Svish
Svish, using the "0" rather than the null worked fined for me. To be safe, try it both ways and use the value that works as expected.
OneSource