C# 按 T​​AB 键时绕过 DataGridView 中的只读单元格

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/751981/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:47:24  来源:igfitidea点击:

Bypass read only cells in DataGridView when pressing TAB key

c#winformsdatagridview

提问by Cornel

Can anyone show me some code of how I could bypass read only cells in DatagridView when pressing TAB key?

任何人都可以向我展示一些代码,说明按下 TAB 键时如何绕过 DatagridView 中的只读单元格?

采纳答案by ChrisF

Overriding the SelectionChanged event is the right approach. The property CurrentCell can be used to set the current cell. You want something like this:

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

You'll need to add a test for the current cell being read only and loop while the next cell is invisible or read only. You'll also need to check to make sure that you don't loop for ever if all cells are read only.

您需要为当前只读的单元格添加一个测试,并在下一个单元格不可见或只读时循环。如果所有单元格都是只读的,您还需要检查以确保您不会永远循环。

You'll have to cope with the case where the display index is different to the base index too.

您还必须处理显示索引与基本索引不同的情况。

To get this behaviour just when pressing Tab you'll need to add a KeyDown handler:

要在按下 Tab 时获得此行为,您需要添加一个 KeyDown 处理程序:

private void AlbumChecker_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Tab)
    {
        SelectNextEditableCell(DataGridView dataGridView);
    }
}

and put the first code in this new method.

并将第一个代码放入这个新方法中。

You might want to check that the DataGridView has focus too.

您可能想检查 DataGridView 是否也有焦点。

回答by Aidan Ryan

Inherit DataGridView and override ProcessDialogKey (for key pressed while editing) and ProcessDataGridViewKey (for key pressed while not editing). When Tab was pressed, set CurrentCell to the next non-readonly cell.

继承 DataGridView 并覆盖 ProcessDialogKey(用于编辑时按下的键)和 ProcessDataGridViewKey(用于未编辑时按下的键)。按下 Tab 键后,将 CurrentCell 设置为下一个非只读单元格。

Optionally override WndProc to filter mouse clicks on readonly cells. (See DataGridView.GetColumnDisplayRectangle to find which column was clicked).

可选择覆盖 WndProc 以过滤鼠标在只读单元格上的点击。(请参阅 DataGridView.GetColumnDisplayRectangle 以查找单击了哪一列)。

Good source to start from here.

这里开始的好来源。

回答by bkwdesign

When the cell is in edit mode, and you want to listen to keystroke events, you might try handling the DataGridView's EditingControlShowing event...

当单元格处于编辑模式,并且您想监听击键事件时,您可以尝试处理 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

Then, in the edtctrlOn_PreviewKeyDown event, you can bubble the arguments over to the original datagrid's PreviewKeyDown event handler.

然后,在 edtctrlOn_PreviewKeyDown 事件中,您可以将参数冒泡到原始数据网格的 PreviewKeyDown 事件处理程序。

回答by Héctor Lazarte

I did an example inheriting DataGridViewclass. The example works for TAB and ENTER keys so the user can quickly insert data, but can still use the mouse or the up, down, right, left keys to select the cells and copy them to an excel. It works simulating several TABs until the Grid gets to a non ReadOnly Cell. Hope it's useful.

我做了一个继承DataGridView类的例子。该示例适用于 TAB 和 ENTER 键,因此用户可以快速插入数据,但仍然可以使用鼠标或向上、向下、向右、向左键选择单元格并将它们复制到 excel。它可以模拟多个选项卡,直到网格到达非只读单元格。希望它有用。

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

回答by Neer

private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e)
{
   if (dataGridView1.CurrentRow.Cells[e.ColumnIndex].ReadOnly)
    {
        SendKeys.Send("{tab}");
    }
}

回答by Steve Rehling

Hector - I hope you are still listening. Your solution is the most elegant and straightforward one I've seen in extensive searching. I've run into the suggestion to override the key events, but your suggestion to invoke base.ProcessTabKey is especially simple and it handles focus passing to the next control when you reach the end of the dgv. The one additional thing your solution needed was a check in MyProcessTabKey for the last cell of the dgv. If that cell is readonly and the user tabs in the previous cell, the while statement goes into an infinite loop. Adding the following code as the first statement in the while loop seems to solve the problem, though it does leave the last (readonly) cell the "active" cell (meaning it appears as though it's selected).

赫克托 - 我希望你还在听。您的解决方案是我在广泛搜索中看到的最优雅、最直接的解决方案。我遇到了覆盖键事件的建议,但是您调用 base.ProcessTabKey 的建议特别简单,它会在您到达 dgv 末尾时处理传递到下一个控件的焦点。您的解决方案需要做的另一件事是检查 MyProcessTabKey 中 dgv 的最后一个单元格。如果该单元格是只读的并且用户在前一个单元格中使用 Tab 键,则 while 语句将进入无限循环。添加以下代码作为 while 循环中的第一条语句似乎解决了问题,尽管它确实将最后一个(只读)单元格保留为“活动”单元格(意味着它看起来好像已被选中)。

    if (this.CurrentCell.RowIndex == this.Rows.Count - 1
                && this.CurrentCell.ColumnIndex == this.Columns.Count - 1)
                { retValue = false; break; } 

I have a follow-on question. Do you or anyone else know how to make this approach work with Shift-Tab, so the dgv skips readonly cells in a backward direction as well? Since Shift and Tab are different key events, I don't know how to detect Shift-Tab in the overridden ProcessDialogKey and ProcessDataGridViewKey methods. Thanks. Steve

我有一个后续问题。您或其他任何人是否知道如何使这种方法与 Shift-Tab 一起使用,以便 dgv 也向后跳过只读单元格?由于 Shift 和 Tab 是不同的键事件,我不知道如何在重写的 ProcessDialogKey 和 ProcessDataGridViewKey 方法中检测 Shift-Tab。谢谢。史蒂夫

回答by Joker

You can catch Tab Key by this code in ProcessDialogKey

您可以在 ProcessDialogKey 中通过此代码捕获 Tab Key

    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

And by this code in ProcessDataGridViewKey

并通过 ProcessDataGridViewKey 中的这段代码

    (e.KeyCode = Keys.Return OrElse e.KeyCode = Keys.Tab) AndAlso e.Modifiers = Keys.Shift

回答by M'Adil Memon

 if (e.KeyValue == 13)
        {
            e = new KeyEventArgs(Keys.Tab);
        }