Search code examples
c#winformsdatagridviewfocuskeypress

How to select next control in winforms from code on TAB pressed inside a Datagridview


I have a strange problem. In Winforms app i have a datagridview where i implemented some code for moving inside of it with arrow keys and enter key...

class CalibDataGridView : System.Windows.Forms.DataGridView
    {
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            int row = 0;
            int col = 0;
            // return base.ProcessCmdKey(ref msg, keyData);
            switch (keyData)
            {
                case Keys.Down:
                    return true;
                case Keys.Up:
                    return true;

                case Keys.Right:
                    row = this.CurrentCell.RowIndex;
                    col = this.CurrentCell.ColumnIndex;

                    while (true)
                    {
                        col++;
                        if (col == this.Columns.Count)
                        {
                            row++;
                            col = 0;
                        }

                        if (row == this.Rows.Count)
                        {
                            col = 0;
                            row = 0;
                        }

                        if (!this[col, row].ReadOnly && this[col, row].Visible) break;
                    }

                    this.CurrentCell = this[col, row];

                    return true;

                case Keys.Left:
                    row = this.CurrentCell.RowIndex;
                    col = this.CurrentCell.ColumnIndex;

                    while (true)
                    {
                        col--;
                        if (col < 0)
                        {
                            row--;
                            col = this.Columns.Count - 1;
                        }

                        if (row < 0)
                        {
                            row = this.Rows.Count - 1;
                            col = this.Columns.Count - 1;
                        }

                        if (!this[col, row].ReadOnly && this[col, row].Visible) break;
                    }

                    this.CurrentCell = this[col, row];

                    return true;

                case Keys.Enter:
                    row = this.CurrentCell.RowIndex;
                    col = this.CurrentCell.ColumnIndex;

                    while (true)
                    {

                            row++;
                        if (row == this.Rows.Count)
                        {
                            row = 0;
                        }

                        if (!this[col, row].ReadOnly && this[col, row].Visible) break;
                    }

                    this.CurrentCell = this[col, row];

                    return true;

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

The code works fine, but i'm having a problem implement function to move to next control when TAB key is pressed. I added some code in PreviewKeyDown function of datagridview:

private void dgvRepeatability1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            if (e.KeyCode == Keys.PageDown && tbcMain.SelectedIndex > 0)
            {
                tbcMain.SelectedIndex--; //changes tab page
            }
            else if (e.KeyCode == Keys.PageUp && tbcMain.SelectedIndex < 7)
            {

                tbcMain.SelectedIndex++;
            }
            else if (e.KeyCode == Keys.Tab) //does not work like it should!!!!
            {
                Console.Beep(1000, 200);
                this.SelectNextControl((Control)sender, true, true, true, true);

            }
        }

This last code works in strange way... when triggered it somewhere in the background changes focus like it should (it beeps and the next control changes background color so i can see it is focused), but then i lose focus on the whole form... i can press TAB or ARROW KEYS or any other key and nothing happens....

If i minimize the form and then maximize it again the focus goes to the next control like it should in the first place and everything works like it should.

I also tryed change focus with .Select() and .Focus() and did not work.

Thanks in advance for help!


Solution

  • You can use SelectNextControl:

    private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
    {
        if ( e.KeyCode == Keys.Tab )
        {
            e.Handled = true; 
            this.SelectNextControl((Control)sender, true, true, true, true);
        }
    

    You can also find the next control yourself:

    private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
    {
        if ( e.KeyCode == Keys.Tab )
        {
            e.Handled = true;
            var dataGrid = (DataGridView) sender;
            var tabIndex = dataGrid.TabIndex;
            var controls = this.Controls.Cast<Control>().Where( r => r.TabIndex > tabIndex );
            if ( controls.Any() )
            {
                controls.OrderBy(r => r.TabIndex).First().Select();
            }
            else
            {
                this.Controls.Cast<Control>()
                             .Where( r => r.TabIndex <= tabIndex )
                             .OrderBy( r => tabIndex )
                             .First()
                             .Select();
            }
        }
    }