25

DataGridView keydown event is not working when I am editing text inside a cell.

I am assigning shortcut Alt+S to save the data, it works when cell is not in edit mode, but if it is in edit mode below code is not working

private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
 {
    if (e.KeyData == (Keys.Alt | Keys.S))
    {
         //save data
    }
 }
Javed Akram
  • 15,024
  • 26
  • 81
  • 118
  • It isn't fired, or the code isn't executed correctly? Can you explain more about what you;re doing? – Rox Nov 26 '10 at 10:23
  • parts of some answers at this link are a bit related- http://stackoverflow.com/questions/686309/datagridview-change-edit-control-size-while-editing/23703744 – barlop May 29 '16 at 03:50
  • This answer works https://stackoverflow.com/questions/70400972/why-cant-i-capture-ctrl-c-in-my-datagridview/70401976#70401976 – Gerry Dec 18 '21 at 17:26

7 Answers7

28

Whenever a cell is in edit mode, its hosted control is receiving the KeyDown event instead of the parent DataGridView that contains it. That's why your keyboard shortcut is working whenever a cell is not in edit mode (even if it is selected), because your DataGridView control itself receives the KeyDown event. However, when you are in edit mode, the edit control contained by the cell is receiving the event, and nothing happens because it doesn't have your custom handler routine attached to it.

I have spent way too much time tweaking the standard DataGridView control to handle edit commits the way I want it to, and I found that the easiest way to get around this phenomenon is by subclassing the existing DataGridView control and overriding its ProcessCmdKey function. Whatever custom code that you put in here will run whenever a key is pressed on top of the DataGridView, regardless of whether or not it is in edit mode.

For example, you could do something like this:

class MyDataGridView : System.Windows.Forms.DataGridView
{
    protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
    {

        MessageBox.Show("Key Press Detected");

        if ((keyData == (Keys.Alt | Keys.S)))
        {
            //Save data
        }

        return base.ProcessCmdKey(ref msg, keyData);
    }
}

Also see related, though somewhat older, article: How to trap keystrokes in controls by using Visual C#

barlop
  • 12,887
  • 8
  • 80
  • 109
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Good advice. The WM_KEYDOWN test isn't necessary btw. – Hans Passant Nov 26 '10 at 15:42
  • @Hans Passant: I agree that it's not necessary, and I normally never include it. I went back to add it after I saw that the article I linked to recommended it as a "good practice." – Cody Gray - on strike Nov 26 '10 at 23:39
  • Typical KB verbiage. You won't know its BS until you put it to the test. 0% hit so far. – Hans Passant Nov 27 '10 at 00:08
  • suppose you have a form, with a)the subclass of datagridview and b)a textbox. And you want the textbox to have the value that is in the edited cell after the key has been pushed down.. Any idea how one would one do that? – barlop May 29 '16 at 03:48
18

Another way of doing it is by using the EditingControlShowing event to redirect the event handling to a custom event handler as below:

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
 {
    if (e.Control is DataGridViewTextBoxEditingControl tb)
            {
                tb.KeyDown -= dataGridView1_KeyDown;
                tb.KeyDown += dataGridView1_KeyDown;
            }
 }

//then in your keydown event handler, execute your code
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
 {
    if (e.KeyData == (Keys.Alt | Keys.S))
    {
         //save data
    }
 }
Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
user2054522
  • 181
  • 1
  • 3
  • 2
    +1: This is the best way for me as I dont want to subclass my DataGridView. – Larry May 22 '14 at 06:49
  • I was not clear on why '-=', I also converted the above to VB.net: `private sub dgvGrid1_editing(sender as Object, e as DataGridViewEditingControlShowingEventArgs) Handles dgvGrid1.EditingControlShowing if Typeof e.Control is DataGridViewTextBoxEditingControl Then Dim tb as DataGridViewTextBoxEditingControl = e.Control AddHandler tb.Keydown, AddressOf dgvGrid1_keydown End if End Sub` – Robert Koernke Sep 07 '17 at 20:59
8

This is true that EditingControlShowing can help, but not if you wants to catch the Enter key. In that case, one should use the following method:

 private void dataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
    {
        if (e.Control is DataGridViewTextBoxEditingControl)
        {
            DataGridViewTextBoxEditingControl tb = e.Control as DataGridViewTextBoxEditingControl;
            tb.KeyDown -= dataGridView_KeyDown;
            tb.PreviewKeyDown -= dataGridView_PreviewKeyDown;
            tb.KeyDown += dataGridView_KeyDown;
            tb.PreviewKeyDown += dataGridView_PreviewKeyDown;
        }
    }

    void dataGridView_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        if (e.KeyData == Keys.Enter)
        {
            <your logic goes here>
        }
    }
Asaf
  • 477
  • 6
  • 6
  • Thanks for the suggestion. I my case I wanted to compare the cell value before the DataGridView.EndEdit and after, but the enter key was committing the value. This way I could not compare. in "" I moved focus to another control and used the Cell_Leave event to calculate the changed values – kuklei Aug 06 '21 at 18:58
3

A simpler way I just tried out is as follows:

  1. Set the KeyPreview property of the Form to true.
  2. Instead of catching the KeyDown event on Grid, catch the KeyDown event on Form.

Code as follows:

Private Sub form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown

   If grd.Focused Then

      'Do your work

   End If

End Sub
boop_the_snoot
  • 3,209
  • 4
  • 33
  • 44
Prashant Agarwal
  • 729
  • 7
  • 23
0

I worked with this

            private void grdViewOrderDetail_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
              {
                grdViewOrderDetail_KeyDown(null,null);
              }

            private void grdViewOrderDetail_KeyDown(object sender, KeyEventArgs e)
              {
    
               //Code                     
              }
Biddut
  • 418
  • 1
  • 6
  • 17
0

The solution class MyDataGridView : System.Windows.Forms.DataGridView { protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) { if ( keyData == Keys.Enter ) { . Process Enter Key . } return base.ProcessCmdKey(ref msg, keyData); } }

Worked perfectly for me

Tony H
  • 61
  • 3
-4

use PreviewKeyDown event

private void dataGridView1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{

}
Javed Akram
  • 15,024
  • 26
  • 81
  • 118