【问题标题】:Bypass read only cells in DataGridView when pressing TAB key按 T​​AB 键时绕过 DataGridView 中的只读单元格
【发布时间】:2009-04-15 14:32:17
【问题描述】:

谁能告诉我一些代码,说明我在按 TAB 键时如何绕过 DatagridView 中的只读单元格?

【问题讨论】:

标签: c# winforms datagridview


【解决方案1】:
private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e)
{
   if (dataGridView1.CurrentRow.Cells[e.ColumnIndex].ReadOnly)
    {
        SendKeys.Send("{tab}");
    }
}

【讨论】:

  • 这是迄今为止最简单的解决方案。我还添加了一个步骤,在 SendKeys 之前的单元格上设置 Selected = False,以消除在网格被分出之前网格中最后一个选定单元格上的视觉伪影。我知道有一个小问题的地方是您是否有 AllowUserToDeleteRows = True 。解决方法是设置 SelectionMode = FullRowSelect ,视觉上并不完美,但相当不错。谢谢
【解决方案2】:

覆盖 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 是否也有焦点。

【讨论】:

  • 但是我想要这种行为只是在按下“TAB”键时而不是在使用鼠标时
  • @Cornel - 不知道该建议什么。你看到什么行为?更多阅读 MSDN 文档中的 DataGridView 方法。这可能需要一些挖掘,但通常信息就在那里。
  • 这是一种实现目标的复杂方式,并非在所有情况下都有效。 DatagridView.ColumnCount 给出了网格视图的列数,包括不可见的列。如果网格视图中有任何不可见的列,则此方法将失败。这可以通过添加更多代码并使方法更加复杂来解决。 @Neer 的解决方案更加准确和优雅。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

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

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

    here开始的好来源。

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        赫克托- 我希望你还在听。您的解决方案是我在广泛搜索中看到的最优雅、最直接的解决方案。我遇到了覆盖关键事件的建议,但是您调用 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 是不同的键事件,我不知道如何在覆盖的 ProcessDialogKey 和 ProcessDataGridViewKey 方法中检测 Shift-Tab。 谢谢。史蒂夫

        【讨论】:

          【解决方案7】:

          您可以通过 ProcessDialogKey 中的此代码捕获 Tab 键

              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
          

          【讨论】:

            【解决方案8】:
             if (e.KeyValue == 13)
                    {
                        e = new KeyEventArgs(Keys.Tab);
                    }
            

            【讨论】:

            • 请考虑包含一些关于您的答案的信息,而不是简单地发布代码。我们试图提供的不仅仅是“修复”,而是帮助人们学习。您应该解释原始代码中的问题、您所做的不同之处以及您的更改为何有效。
            猜你喜欢
            • 2020-03-23
            • 2010-10-30
            • 1970-01-01
            • 2017-03-17
            • 1970-01-01
            • 2012-01-06
            • 1970-01-01
            • 2013-11-13
            • 1970-01-01
            相关资源
            最近更新 更多