Может ли кто-нибудь показать мне код того, как я могу обойти ячейки только для чтения в DatagridView при нажатии клавиши TAB?
Обход ячеек только для чтения в DataGridView при нажатии клавиши TAB
Ответы (8)
Правильным подходом является переопределение события SelectionChanged. Свойство CurrentCell можно использовать для установки текущей ячейки. Вы хотите что-то вроде этого:
private void dataGridView_SelectionChanged(object sender, EventArgs e)
{
DataGridViewCell currentCell = dataGridView.CurrentCell;
if (currentCell != null)
{
int nextRow = currentCell.RowIndex;
int nextCol = currentCell.ColumnIndex + 1;
if (nextCol == dataGridView.ColumnCount)
{
nextCol = 0;
nextRow++;
}
if (nextRow == dataGridView.RowCount)
{
nextRow = 0;
}
DataGridViewCell nextCell = dataGridView.Rows[nextRow].Cells[nextCol];
if (nextCell != null && nextCell.Visible)
{
dataGridView.CurrentCell = nextCell;
}
}
}
Вам нужно будет добавить тест для текущей ячейки только для чтения и цикла, пока следующая ячейка невидима или доступна только для чтения. Вам также нужно будет убедиться, что вы не зацикливаетесь навсегда, если все ячейки доступны только для чтения.
Вам также придется иметь дело со случаем, когда отображаемый индекс отличается от базового индекса.
Чтобы получить такое поведение только при нажатии Tab, вам нужно добавить обработчик KeyDown:
private void AlbumChecker_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Tab)
{
SelectNextEditableCell(DataGridView dataGridView);
}
}
и поместите первый код в этот новый метод.
Возможно, вы захотите проверить, что DataGridView также имеет фокус.
Я сделал пример, наследующий класс DataGridView
. Пример работает для клавиш TAB и ENTER, поэтому пользователь может быстро вставлять данные, но по-прежнему может использовать мышь или клавиши вверх, вниз, вправо, влево для выбора ячеек и копирования их в Excel. Он работает, имитируя несколько TAB, пока Grid не перейдет в ячейку, не предназначенную только для чтения. Надеюсь, это полезно.
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace System.Windows.Forms
{
class MyDataGridView : DataGridView
{
protected override bool ProcessDialogKey(Keys keyData)
{
if (keyData == Keys.Enter || keyData == Keys.Tab)
{
MyProcessTabKey(Keys.Tab);
return true;
}
return base.ProcessDialogKey(keyData);
}
protected override bool ProcessDataGridViewKey(KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab)
{
MyProcessTabKey(Keys.Tab);
return true;
}
return base.ProcessDataGridViewKey(e);
}
protected bool MyProcessTabKey(Keys keyData)
{
bool retValue = base.ProcessTabKey(Keys.Tab);
while (this.CurrentCell.ReadOnly)
{
retValue = base.ProcessTabKey(Keys.Tab);
}
return retValue;
}
}
}
Унаследуйте DataGridView и переопределите ProcessDialogKey (для нажатия клавиши во время редактирования) и ProcessDataGridViewKey (для клавиши, нажатой без редактирования). При нажатии Tab установите CurrentCell на следующую ячейку, не предназначенную только для чтения.
При необходимости переопределите WndProc для фильтрации щелчков мышью по ячейкам, доступным только для чтения. (См. DataGridView.GetColumnDisplayRectangle, чтобы узнать, какой столбец был нажат).
Хороший источник для начала с здесь а>.
Когда ячейка находится в режиме редактирования и вы хотите прослушивать события нажатия клавиш, вы можете попробовать обработать событие DataGridView EditingControlShowing...
Private Sub myDvGrid_EditingControlShowing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles myDvGrid.EditingControlShowing
Dim c As DataGridViewTextBoxEditingControl = DirectCast(e.Control, DataGridViewTextBoxEditingControl)
RemoveHandler c.PreviewKeyDown, AddressOf edtctrlOn_PreviewKeyDown
RemoveHandler c.TextChanged, AddressOf edtctrlOn_TextChanged
AddHandler c.TextChanged, AddressOf edtctrlOn_TextChanged
AddHandler c.PreviewKeyDown, AddressOf edtctrlOn_PreviewKeyDown
End Sub
Затем в событии edtctrlOn_PreviewKeyDown можно передать аргументы обработчику событий PreviewKeyDown исходной сетки данных.
Гектор – Надеюсь, ты все еще слушаешь. Ваше решение - самое элегантное и простое, которое я видел в обширном поиске. Я столкнулся с предложением переопределить ключевые события, но ваше предложение вызвать base.ProcessTabKey особенно просто и обрабатывает передачу фокуса следующему элементу управления, когда вы достигаете конца dgv. Одной дополнительной вещью, которая требовалась вашему решению, была проверка MyProcessTabKey для последней ячейки dgv. Если эта ячейка доступна только для чтения и пользователь вводит вкладку в предыдущей ячейке, инструкция while переходит в бесконечный цикл. Добавление следующего кода в качестве первого оператора в цикле while, по-видимому, решает проблему, хотя последняя (доступная только для чтения) ячейка остается «активной» ячейкой (это означает, что она выглядит так, как будто она выбрана).
if (this.CurrentCell.RowIndex == this.Rows.Count - 1
&& this.CurrentCell.ColumnIndex == this.Columns.Count - 1)
{ retValue = false; break; }
У меня вопрос вдогонку. Знаете ли вы или кто-либо еще, как заставить этот подход работать с Shift-Tab, чтобы dgv также пропускал ячейки только для чтения в обратном направлении? Поскольку Shift и Tab — это разные ключевые события, я не знаю, как определить Shift-Tab в переопределенных методах ProcessDialogKey и ProcessDataGridViewKey. Спасибо. Стив
Вы можете поймать клавишу Tab по этому коду в ProcessDialogKey
Dim uKeyCode As Keys = (keyData And Keys.KeyCode)
Dim uModifiers As Keys = (keyData And Keys.Modifiers)
(uKeyCode = Keys.Return OrElse uKeyCode = Keys.Tab) AndAlso uModifiers = Keys.Shift
И по этому коду в ProcessDataGridViewKey
(e.KeyCode = Keys.Return OrElse e.KeyCode = Keys.Tab) AndAlso e.Modifiers = Keys.Shift