DataGridView KeyDown manipulation (enter, left, right, etc.) not working when multiselect

949 views Asked by At

I want to make the DataGridView more handy while manipulating the KeyDown event, like the KeyEnter for moving one cell to the right, or using left, down or up. I have some special use cases where I want to check first the cell and depending on that I can discard this event for example or point it to an another cell. This is working fine until I set the "multiselect" feature to true. Then the complete process of leaving focus and set the right focus, per cell is not working fine anymore. Please find some sample code below:

private bool GridNavigation(Keys keys)
    {
        if (dataGridView1.CurrentRow == null)
        {
            return true;
        }

        int iColumn = dataGridView1.CurrentCell.ColumnIndex;
        int iRow = dataGridView1.CurrentCell.RowIndex;

        if (keys == Keys.Enter || keys == Keys.Right)
        {
                for (int i = iColumn + 1; i <= dataGridView1.Columns.Count - 4; i++)
                {
                    if (!dataGridView1.Rows[iRow].Cells[i].ReadOnly)
                    {
                        dataGridView1.Rows[iRow].Cells[i].Selected = true;
                        break;
                    }
                    if (i == dataGridView1.Columns.Count - 4 && dataGridView1.Rows.Count - 1 != iRow)
                    {
                        if (((IDictionary<int, int>)dataGridView1.CurrentRow.Tag).SingleOrDefault(p => p.Key == (int)clsDefinitions.ZeilenIndikator.Typ).Value == (int)clsDefinitions.ZeilenTyp.PassLängeAusgangswert)
                            dataGridView1.CurrentCell = dataGridView1[0, iRow + 2];
                        else
                            dataGridView1.CurrentCell = dataGridView1[0, iRow + 1];
                        return true;
                    }
            }
            return true;
        }
        else if (keys == Keys.Left)
        {
            for (int i = iColumn - 1; i >= 0; i--)
            {
                if (!dataGridView1.Rows[iRow].Cells[i].ReadOnly)
                {
                    dataGridView1.Rows[iRow].Cells[i].Selected = true;
                    break;
                }
            }
            return true;
        }
        else
            return false;
    }

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        if (keyData == Keys.Enter || keyData == Keys.Right || keyData == Keys.Left)
        {
            return GridNavigation(keyData);
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }

So what can be done here. You can easily reproduce by open a new Project and just put a DataGridView in the form and add for example 10 columns or more.

If there's something else I can provide, please let me know.

2

There are 2 answers

1
OhBeWise On BEST ANSWER

In your GridNavigation method, under both conditions, if (keys == Keys.Enter || keys == Keys.Right) and else if (keys == Keys.Left), the guilty party here is the recurring line:

dataGridView1.Rows[iRow].Cells[i].Selected = true;

What went wrong?

When dataGridView1.MultiSelect == false the above line effectively sets the current cell, not just the Selected property. I.E:

  1. CurrentCell = Rows[0].Cells[0], Rows[0].Cells[0].Selected = true
  2. User clicks -> or Enter
    • Rows[0].Cells[1].Selected = true
    • CurrentCell = Rows[0].Cells[1]
    • Rows[0].Cells[0].Selected = false

However, when dataGridView1.MultiSelect == true the same line of code does not set the current cell. So the current cell remains selected as well as the adjoining cell to the left or right respectively. I.E:

  1. CurrentCell = Rows[0].Cells[0], Rows[0].Cells[0].Selected = true
  2. User clicks -> or Enter
    • Rows[0].Cells[1].Selected = true
    • CurrentCell = Rows[0].Cells[0]
    • Rows[0].Cells[0].Selected = true
  3. User again clicks -> or Enter
    • Expected results: Rows[0].Cells[2].Selected = true.
    • Actual results: Rows[0].Cells[1].Selected = true ...again.

Solution

If you want it to behave the same as MultiSelect = false and only have one selected cell when you navigate left or right, just replace the guilty lines of code with:

dataGridView1.CurrentCell = dataGridView.Rows[iRow].Cells[i];

If you want to retain the previously selected cells, replace the guilty lines of code with:

DataGridViewSelectedCellCollection cells = dataGridView1.SelectedCells;
dataGridView1.CurrentCell = dataGridView1.Rows[iRow].Cells[i];

if (dataGridView1.MultiSelect)
{
  foreach (DataGridViewCell cell in cells)
  {
    cell.Selected = true;
  }
}
0
Graffito On

Did you set the selection mode?

dataGridView1.SelectionMode = DataGridViewSelectionMode.CellSelect;