4

Вопрос по datagridviewtextboxcell, keydown, datagridview, windows, c# – Как программно перейти из одной ячейки в сетке данных в другую?

Мне нужно разрешить ввод только одного символа в редактируемые ячейки таблицы данных (все остальные столбцы, нечетные, редактируются); если пользователь добавляет второй символ, находясь в одной из этих ячеек, курсор должен переместиться на следующую ячейку вниз и поместить туда второе значение (повторное нажатие на эту клавишу снова перемещается вниз и т. д.). Если в нижней части сетки (12-й ряд), он должен переместиться в строку 0, а также переместить два столбца вправо.

Я пытался сделать это:

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;
        }
    }
}

... но я получаю сообщения об ошибках, которые нельзя назначить RowIndex и ColumnIndex, так как они доступны только для чтения.

Так как я могу это сделать?

Предостережение: я знаю, что мне также нужно будет добавить логику, чтобы перейти к столбцу 1, если в данный момент он находится внизу последнего редактируемого столбца.

UPDATE

Из ответа tergiver'а это то, что я до сих пор получил, но я не знаю, как перейти к следующей ячейке.

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

Спасибо всем; это то, что я использую, чтобы заставить его работать в значительной степени (я все еще хочу иметь возможность позволить пользователю просто удерживать клавишу, и чтобы это значение непрерывно вводилось в последующих ячейках):

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];
        }
    }
}
  • @ClayShannon Я должен отметить, что изменение касается управления редактированием, а не DGV, для второго символа, затем изменения выделения, а затем повторной отправки сообщения WM_KEYDOWN в DGV, чтобы оно активировало следующий элемент управления редактирования на месте. ,

    от
  • @ClayShannon Выше работает, я проверял.

    от
  • Хорошо, но как мне изменить текущую ячейку? Мои вышеописанные попытки потерпели неудачу / не скомпилируются. Я обновил свой оригинальный пост выше.

    от B. Clay Shannon
  • Я попытался добавить эту логику, но она не работает: if (currentCell.Value.ToString (). Length & gt; 0) {rowIndex = rowIndex + 1; }

    от B. Clay Shannon
  • @ClayShannon Проверьте обновление

    от
  • Я попробовал это, и это не сработало: int colIndex = dataGridViewPlatypus.CurrentCell.ColumnIndex; int rowIndex = dataGridViewPlatypus.CurrentCell.RowIndex; TextBox tb = отправитель как TextBox; if (tb.TextLength & gt; = 1) {dataGridViewPlatypus.Rows [rowIndex + 1] .Cells [colIndex] .Selected = true; }

    от B. Clay Shannon
  • Я не вижу, как это сделать.

    от B. Clay Shannon
  • @ClayShannon см. Редактировать.

    от
  • Посмотрели ли вы SendKeys.Send (& quot; {Имя вашего ключа ID} & quot;) Вы можете отправить ввод, вкладку, вверх, вниз и т. Д., Где угодно и когда угодно

    от Sami
  • 1

    Клетки имеют

    Selected свойство, которое вы можете установить. Просто получите доступ к ячейке по столбцу и индексу строки.

    Я верю, что ты можешь просто сделать

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

    который даст вам ячейку в (0,0) или в первой строке, первый столбец пересекается. Или вы можете взять строку следующим образом:

    Я думаю, что это класс - & gt;DataGridViewRow row = dgView.rows[0]

    а потом

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

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

    Чтобы закончить следующую ячейку, просто сделайте:

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

    Возможно, я пропустил некоторые заглавные буквы там, но вы поняли.

  • 3

    CurrentCell собственностьDataGridView имеет установщик, позволяющий перейти в новую ячейку.

    Один из подходов к этой проблеме заключается вEditingControlShowing событие сетки и прикрепитьKeyPress обработчик для элемента управления редактирования так:

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

    Тогда в обработчике нажатия клавиш у вас есть:

    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];
         }
    }
    

    Вышеприведенная логика, конечно, не верна для вашего случая, но принцип передачи нового CurrentCell (после извлечения нужной ячейки из сетки) остается в силе.

  • 1

    KeyDown на DGV не будет работать

    потому что DataGridViewTextBoxColumn использует встроенный элемент управления TextBox, который он делает видимым и перемещается на место как раз вовремя для редактирования.

    Поскольку для всех текстовых столбцов имеется только один TextBox на месте, вы можете подписаться на его событие KeyDown, но при получении ссылки на этот элемент управления могут возникнуть проблемы с яйцами.

    Лучше было бы использовать переопределение ProcessCmdKey формы и выполнять эту логику там. Когда происходит нажатие клавиши, проверьте, является ли DGV ActiveControl, проверьте, является ли текущая ячейка текстовой ячейкой, проверьте, содержит ли ячейка символ, а затем измените текущую ячейку, прежде чем разрешить обработку ключа.

    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);
        }
    }