How can I programmatically move from one cell in a datagridview to another?

B. Clay Shannon picture B. Clay Shannon · Aug 31, 2012 · Viewed 9.2k times · Source

I need to only allow one character to be entered into the editable datagridview cells (every other column, the odd-numbered ones, are editable); if the user adds a second character while in one of these cells, the cursor should move to the next cell down and put that second value there (pressing again on that key moves down again, and so forth). If at the bottom of the grid (the 12th row), it should move to row 0 and also move two columns to the right.

I tried doing this:

private void dataGridViewPlatypus_KeyDown(object sender, KeyEventArgs e) {
    var currentCell = dataGridViewPlatypus.CurrentCell;
    int currentCol = currentCell.ColumnIndex;
    int currentRow = currentCell.RowIndex;
    if (currentCell.Value.ToString().Length > 0) {
        if (currentRow < 11) {
            dataGridViewPlatypus.CurrentCell.RowIndex = currentRow+1;
        } else if (currentRow == 11) {
            currentCell.RowIndex = 0;
            currentCell.ColumnIndex = currentCell.ColumnIndex + 2;
            dataGridViewPlatypus.CurrentCell = currentCell;
        }
    }
}

...but I get err msgs that RowIndex and ColumnIndex cannot be assigned to, as they are readonly.

So how can I accomplish this?

Caveat: I know that I will also have to add logic to move to column 1 if currently at the bottom of the last editable column.

UPDATE

From tergiver's answer, this is what I've got so far, but I don't know how to advance to the next cell.

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
    if (this.ActiveControl == dataGridViewPlatypus)
    {
        var currentCell = dataGridViewPlatypus.CurrentCell;
        if (currentCell.Value.ToString().Length == 1) 
        {
            ;//Now what?
        }
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

UPDATE 2

Thanks all; this is what I'm using to get it pretty much working (I still want to be able to allow the user to simply hold the key down, and have that value continuously entered in subsequent cells):

private void dataGridViewPlatypus_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
    int columnIndex = (((DataGridView)(sender)).CurrentCell.ColumnIndex);
    if (columnIndex % 2 == 1) {
        e.Control.KeyDown -= TextboxNumeric_KeyDown;
        e.Control.KeyDown += TextboxNumeric_KeyDown;
        e.Control.KeyUp -= TextboxNumeric_KeyUp;
        e.Control.KeyUp += TextboxNumeric_KeyUp;
    }
}

private void TextboxNumeric_KeyDown(object sender, KeyEventArgs e) {
    var tb = sender as TextBox;
    if (tb != null) {
        tb.MaxLength = 1;
    }
}

// TODO: Now need to find a way to be able to just press down once
private void TextboxNumeric_KeyUp(object sender, KeyEventArgs e) {
    var tb = sender as TextBox;
    if (tb != null && tb.TextLength >= 1) {
        if (dataGridViewPlatypus.CurrentCell.RowIndex != dataGridViewPlatypus.Rows.Count - 1) {
            dataGridViewPlatypus.CurrentCell = dataGridViewPlatypus[
                dataGridViewPlatypus.CurrentCell.ColumnIndex,
                dataGridViewPlatypus.CurrentCell.RowIndex + 1];
        } else { // on last row
            this.dataGridViewPlatypus.CurrentCell = this.dataGridViewPlatypus.CurrentCell.ColumnIndex !=    dataGridViewPlatypus.Columns.Count - 1 ? this.dataGridViewPlatypus[this.dataGridViewPlatypus.CurrentCell.ColumnIndex    + 2, 0] : this.dataGridViewPlatypus[1, 0];
        }
    }
}

Answer

David Hall picture David Hall · Aug 31, 2012

The CurrentCell property of the DataGridView has a setter, allowing you to pass in a new cell.

One approach to this problem is to handle the EditingControlShowing event of the grid and attach a KeyPress handler to the editing control like so:

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{                
    if ((int)(((System.Windows.Forms.DataGridView)(sender)).CurrentCell.ColumnIndex) == 1)
    {
        e.Control.KeyPress += TextboxNumeric_KeyPress;
    }
}

Then in the key press handler you have:

private void TextboxNumeric_KeyPress(object sender, KeyPressEventArgs e)
{
    TextBox tb = sender as TextBox;
     if (tb.TextLength >= 5)
     {
         dataGridView1.CurrentCell = dataGridView1[dataGridView1.CurrentCell.ColumnIndex + 1, dataGridView1.CurrentCell.RowIndex];
     }
}

The logic above is of course not correct for your case but the principle of passing in a new CurrentCell (after retrieving the desired cell from the grid) stands.