Обход ячеек только для чтения в DataGridView при нажатии клавиши TAB

Может ли кто-нибудь показать мне код того, как я могу обойти ячейки только для чтения в DatagridView при нажатии клавиши TAB?


person Cornel    schedule 15.04.2009    source источник


Ответы (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 также имеет фокус.

person ChrisF    schedule 15.04.2009
comment
но я хочу, чтобы это поведение происходило только при нажатии клавиши «TAB», а не при использовании мыши. - person Cornel; 15.04.2009
comment
@Cornel - действительно не знаю, что предложить. Какое поведение вы видите? Почитайте еще немного о методах DataGridView в документации MSDN. Это может занять некоторое время, но обычно информация есть. - person ChrisF; 16.04.2009
comment
Это запутанный способ достижения цели, и он работает не во всех случаях. DatagridView.ColumnCount дает количество столбцов для представления сетки, включая невидимые столбцы. Если в представлении сетки есть какие-либо невидимые столбцы, этот метод не работает. Это можно решить, добавив еще немного кода и сделав метод еще более запутанным. Решение @Neer ниже намного точнее и элегантнее. - person Dewald Swanepoel; 09.10.2017

Я сделал пример, наследующий класс 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;
    }
  }
}
person Héctor Lazarte    schedule 03.09.2010

Унаследуйте DataGridView и переопределите ProcessDialogKey (для нажатия клавиши во время редактирования) и ProcessDataGridViewKey (для клавиши, нажатой без редактирования). При нажатии Tab установите CurrentCell на следующую ячейку, не предназначенную только для чтения.

При необходимости переопределите WndProc для фильтрации щелчков мышью по ячейкам, доступным только для чтения. (См. DataGridView.GetColumnDisplayRectangle, чтобы узнать, какой столбец был нажат).

Хороший источник для начала с здесь .

person Aidan Ryan    schedule 28.04.2009

Когда ячейка находится в режиме редактирования и вы хотите прослушивать события нажатия клавиш, вы можете попробовать обработать событие 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 исходной сетки данных.

person bkwdesign    schedule 10.12.2009

Гектор – Надеюсь, ты все еще слушаешь. Ваше решение - самое элегантное и простое, которое я видел в обширном поиске. Я столкнулся с предложением переопределить ключевые события, но ваше предложение вызвать 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. Спасибо. Стив

person Steve Rehling    schedule 28.04.2012

Вы можете поймать клавишу 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
person Joker    schedule 03.04.2014

person    schedule
comment
Это, безусловно, самое простое решение. Я также добавил шаг, чтобы установить Selected = False в ячейке перед SendKeys, чтобы избавиться от визуального артефакта в последней выбранной ячейке в сетке до выхода из сетки. Я знаю одно место, где есть небольшая проблема, если у вас AllowUserToDeleteRows = True . Обходной путь состоит в том, чтобы установить SelectionMode = FullRowSelect , не идеально визуально, но довольно хорошо. Спасибо - person Jay13; 21.12.2016

person    schedule
comment
Пожалуйста, рассмотрите возможность включения некоторой информации о вашем ответе, а не просто размещение кода. Мы пытаемся предоставлять не только «исправления», но и помогать людям учиться. Вы должны объяснить, что было не так в исходном коде, что вы сделали по-другому и почему ваши изменения сработали. - person Andrew Barber; 21.08.2014