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

穿精又带淫゛_ 提交于 2019-12-01 20:06:20

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.

The cells have a Selected property you can set. Just access the cell by column and row index.

I believe you can just do

dgView.rows[0].cells[0].selected = true,

which will give you the cell at (0,0) or first row, first column intersect. Or, you can grab the row like this:

I think that's the class -->DataGridViewRow row = dgView.rows[0]

and then

row[0].cells[0].Selected = true.

       Column 1  Column 2
Row 1 [this guy][        ]
Row 2 [        ][        ]

EDIT:

To get the next cell over, just do:

sameRow.cells[currentCell.ColumnIndex+1].Selected = true;

I may have missed some capitalizations in there, but you get the point.

KeyDown on the DGV won't work because a DataGridViewTextBoxColumn uses an in-place TextBox control which it makes visible and moves into place just in time for editing.

Since there is only one in-place TextBox for all text columns, you could subscribe to its KeyDown event, but there may be chicken and egg issue with obtaining a reference to that control.

Better would be to use the Form's ProcessCmdKey override and perform this logic there. When a key down occurs, check if the DGV is the ActiveControl, check if the current cell is a text cell, check if the cell already contains a character, then change the current cell before allowing the key to be processed.

Updated - Take 2

using System;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;

class Item
{
    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }
    public string D { get; set; }
}

class Form1 : Form
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    DataGridView dataGridViewPlatypus;

    public Form1()
    {
        ClientSize = new Size(480, 260);
        Controls.Add(dataGridViewPlatypus = new DataGridView
        {
            Dock = DockStyle.Fill,
            DataSource = Enumerable.Range(1, 10).Select(i => new Item { A = "", B = "", C = "", D = "" }).ToList(),
        });
    }

    [DllImport("User32.dll")]
    extern static int PostMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        if (msg.Msg == 256) // WM_KEYDOWN
        {
            if (this.ActiveControl == dataGridViewPlatypus.EditingControl)
            {
                var currentCell = dataGridViewPlatypus.CurrentCell;
                if (currentCell.OwningColumn is DataGridViewTextBoxColumn && dataGridViewPlatypus.EditingControl.Text.Length > 0)
                {
                    int rowIndex = currentCell.RowIndex;
                    int columnIndex = currentCell.ColumnIndex;

                    if (++columnIndex >= dataGridViewPlatypus.Columns.Count)
                    {
                        columnIndex = 0;
                        if (++rowIndex >= dataGridViewPlatypus.Rows.Count)
                            rowIndex = 0;
                    }

                    dataGridViewPlatypus.CurrentCell = dataGridViewPlatypus[columnIndex, rowIndex];
                    PostMessage(dataGridViewPlatypus.Handle, msg.Msg, msg.WParam, msg.LParam);
                    return true; // Don't process this message, we re-sent it to the DGV
                }
            }
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }
}

I have a process that bombs if the selected cell is in column one. So in the code for the button for that process, this is the first code in it: (BTW, I use cell selection in the grid)

if (dgvGrid.CurrentCell.ColumnIndex == 0) // first column
    dgvGrid.Rows[dgvGrid.CurrentCell.RowIndex].Cells[1].Selected = true;

This effectively "tabs" to the next column, and then the rest of my process works.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!