Datagridview:如何在编辑模式下设置单元格?

Posted

技术标签:

【中文标题】Datagridview:如何在编辑模式下设置单元格?【英文标题】:Datagridview: How to set a cell in editing mode? 【发布时间】:2010-12-21 07:52:45 【问题描述】:

我需要以编程方式将单元格设置为编辑模式。我知道将该单元格设置为 CurrentCell,然后调用方法 BeginEdit(bool),它应该会发生,但在我的情况下,它不会。

我真的想要这样,我的 DGV 有几列,用户只能选择和编辑前两列。其他列已经是只读的,但用户可以选择它们,这是我不想要的。

所以我在想,每次在单元格上写完后告诉用户 TAB,然后选择第二个单元格,然后再次 Tab 并选择并开始编辑下一行的第一个单元格...

我该怎么做?

【问题讨论】:

【参考方案1】:

好吧,我会检查您的任何列是否设置为ReadOnly。我从来没有使用过 BeginEdit,但也许有一些合法的用途。完成dataGridView1.Columns[".."].ReadOnly = False; 后,不是ReadOnly 的字段应该是可编辑的。您可以使用 DataGridView CellEnter 事件来确定输入了哪些单元格,然后在将编辑从前两列传递到下一组列并关闭编辑后打开对这些单元格的编辑在最后两列。

【讨论】:

【参考方案2】:

设置CurrentCell 然后调用BeginEdit(true) 对我来说效果很好。

以下代码显示了KeyDown 事件的事件处理程序,它将单元格设置为可编辑。

我的示例仅实现了所需的按键覆盖之一,但理论上其他的应该工作相同。 (我总是将 [0][0] 单元格设置为可编辑,但任何其他单元格都应该可以工作)

    private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
    
        if (e.KeyCode == Keys.Tab && dataGridView1.CurrentCell.ColumnIndex == 1)
        
            e.Handled = true;
            DataGridViewCell cell = dataGridView1.Rows[0].Cells[0];
            dataGridView1.CurrentCell = cell;
            dataGridView1.BeginEdit(true);               
        
    

如果您以前没有找到它,DataGridView FAQ 是一个很好的资源,由 DataGridView 控件的程序经理编写,它涵盖了您可以对控件执行的大部分操作。

【讨论】:

谢谢...首先我尝试使用 SelectionChange 事件,并做了一些艰苦的(也很丑陋)工作以避免堆栈溢出,因为每次选择更改它都会再次触发。但是现在,我最喜欢您的解决方案...感谢 +1 的常见问题解答。我更习惯于 web 而不是 winforms,但无论如何都很高兴知道。谢谢! 这正是我所需要的。有点... :) 我实际上是在尝试从绑定到数据源的网格外部更新单元格内容。我可以将新值放在屏幕上,但保存按钮正在保存旧值。我需要在更新值之前和 EndEdit() 之前放置一个 CurrentCell。你的回答让我完全走上了正轨。谢谢! 避免了问类似问题的需要 - ty 您可以信任的文档:“Windows Froms 2.0”-FAQ 文档,第一句。 @KevinDeLorey ha,从未注意到!除了错字,它实际上值得一看:)【参考方案3】:
private void DgvRoomInformation_CellEnter(object sender, DataGridViewCellEventArgs e)

  if (DgvRoomInformation.CurrentCell.ColumnIndex == 4)  //example-'Column index=4'
  
    DgvRoomInformation.BeginEdit(true);   
  

【讨论】:

【参考方案4】:

我知道这个问题已经很老了,但我想我会分享一些这个问题帮助我解决的演示代码。

使用ButtonDataGridView 创建一个表单 为 button1 注册一个Click 事件 为 DataGridView1 注册 CellClick 事件 将 DataGridView1 的属性 EditMode 设置为 EditProgrammatically 将以下代码粘贴到 Form1 中:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1

    public partial class Form1 : Form
    
        DataTable m_dataTable;
        DataTable table  get  return m_dataTable;  set  m_dataTable = value;  

        private const string m_nameCol = "Name";
        private const string m_choiceCol = "Choice";

        public Form1()
        
            InitializeComponent();
        

        class Options
        
            public int m_Index  get; set; 
            public string m_Text  get; set; 
        

        private void button1_Click(object sender, EventArgs e)
        
            table = new DataTable();
            table.Columns.Add(m_nameCol);
            table.Rows.Add(new object[]  "Foo" );
            table.Rows.Add(new object[]  "Bob" );
            table.Rows.Add(new object[]  "Timn" );
            table.Rows.Add(new object[]  "Fred" );

            dataGridView1.DataSource = table;

            if (!dataGridView1.Columns.Contains(m_choiceCol))
            
                DataGridViewTextBoxColumn txtCol = new DataGridViewTextBoxColumn();
                txtCol.Name = m_choiceCol;
                dataGridView1.Columns.Add(txtCol);
            

            List<Options> oList = new List<Options>();
            oList.Add(new Options()  m_Index = 0, m_Text = "None" );
            for (int i = 1; i < 10; i++)
            
                oList.Add(new Options()  m_Index = i, m_Text = "Op" + i );
            

            for (int i = 0; i < dataGridView1.Rows.Count - 1; i += 2)
            
                DataGridViewComboBoxCell c = new DataGridViewComboBoxCell();

                //Setup A
                c.DataSource = oList;
                c.Value = oList[0].m_Text;
                c.ValueMember = "m_Text";
                c.DisplayMember = "m_Text";
                c.ValueType = typeof(string);

                ////Setup B
                //c.DataSource = oList;
                //c.Value = 0;
                //c.ValueMember = "m_Index";
                //c.DisplayMember = "m_Text";
                //c.ValueType = typeof(int);

                //Result is the same A or B
                dataGridView1[m_choiceCol, i] = c;
            
        

        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        
            if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
            
                if (dataGridView1.CurrentCell.ColumnIndex == dataGridView1.Columns.IndexOf(dataGridView1.Columns[m_choiceCol]))
                
                    DataGridViewCell cell = dataGridView1[m_choiceCol, e.RowIndex];
                    dataGridView1.CurrentCell = cell;
                    dataGridView1.BeginEdit(true);
                
            
        
    

请注意,列索引号可以通过按下按钮一的多个按钮来改变,所以我总是按名称而不是索引值来引用列。我需要将 David Hall 的答案合并到我已经有 ComboBoxes 的演示中,所以他的答案非常有效。

【讨论】:

【参考方案5】:

我知道这是一个老问题,但没有一个答案对我有用,因为我希望在可能执行其他事件(如工具栏按钮单击、菜单选择、等可能会影响这些事件返回后的默认焦点。我最终需要一个计时器并调用。以下代码位于从 DataGridView 派生的新组件中。这段代码让我可以随时调用myXDataGridView.CurrentRow_SelectCellFocus(myDataPropertyName); 任意将数据绑定单元格设置为编辑模式(假设单元格不是只读模式)。

// If the DGV does not have Focus prior to a toolbar button Click, 
// then the toolbar button will have focus after its Click event handler returns.
// To reliably set focus to the DGV, we need to time it to happen After event handler procedure returns.

private string m_SelectCellFocus_DataPropertyName = "";
private System.Timers.Timer timer_CellFocus = null;

public void CurrentRow_SelectCellFocus(string sDataPropertyName)

  // This procedure is called by a Toolbar Button's Click Event to select and set focus to a Cell in the DGV's Current Row.
  m_SelectCellFocus_DataPropertyName = sDataPropertyName;
  timer_CellFocus = new System.Timers.Timer(10);
  timer_CellFocus.Elapsed += TimerElapsed_CurrentRowSelectCellFocus;
  timer_CellFocus.Start();



void TimerElapsed_CurrentRowSelectCellFocus(object sender, System.Timers.ElapsedEventArgs e)

  timer_CellFocus.Stop();
  timer_CellFocus.Elapsed -= TimerElapsed_CurrentRowSelectCellFocus;
  timer_CellFocus.Dispose();
  // We have to Invoke the method to avoid raising a threading error
  this.Invoke((MethodInvoker)delegate
  
    Select_Cell(m_SelectCellFocus_DataPropertyName);
  );



private void Select_Cell(string sDataPropertyName)

  /// When the Edit Mode is Enabled, set the initial cell to the Description
  foreach (DataGridViewCell dgvc in this.SelectedCells) 
  
    // Clear previously selected cells
    dgvc.Selected = false; 
  
  foreach (DataGridViewCell dgvc in this.CurrentRow.Cells)
  
    // Select the Cell by its DataPropertyName
    if (dgvc.OwningColumn.DataPropertyName == sDataPropertyName)
    
      this.CurrentCell = dgvc;
      dgvc.Selected = true;
      this.Focus();
      return;
    
  

【讨论】:

【参考方案6】:

我终于找到了答案。就我而言,我想在添加新行后选择特定的索引或项目,但这应该适用于其他情况。

每个单元格不包含组合框控件。 DGV 确实如此,它拥有当前单元的控制权。因此,您必须将当前单元格设为组合单元格,然后进入编辑模式,然后将 dgv 控件转换为 ComboBox,然后您将可以访问 selectedIndex 和 selectedItem 方法

Dim rowIndex = myDgv.Rows.Add()
myDgv.ClearSelection()
myDgv.CurrentCell = myDgv.Rows(rowIndex).Cells("colName")
myDgv.BeginEdit(True)
Dim myCombo as ComboBox = CType(myDgv.EditingControl, ComboBox)
myCombo.SelectedIndex = 3

【讨论】:

以上是关于Datagridview:如何在编辑模式下设置单元格?的主要内容,如果未能解决你的问题,请参考以下文章

在可编辑单元格中写入值时如何捕获 DataGridView 验证错误?

DataGridView:编辑时更改编辑控件大小

如何验证 DataGridView 中单元格编辑控件的输入?

如何使用辅助文本框编辑 datagridview 单元格?

asp.net(C#) datagridview 如何实现单元格值更改后自动触发事件

在c#中编辑datagridview后如何更新我的数据库