从DataGridView中用户添加的行中获取值 [英] Getting values from user added row in DataGridView

查看:46
本文介绍了从DataGridView中用户添加的行中获取值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在用户添加一些行后从行中获取价值.

我已经看到此问题

您声明当用户将"某些值添加"到新行"中的一个单元格中时,要从单元格中获取数据值.具体来说,在您发布的代码中,您似乎希望从单元格零(0)处的新行"中获取数据.

这是可行的,但是正如注释和您当前的困境所指出的那样,您需要小心使用使用"哪些事件,更具体地说,在事件触发时该做什么做什么",尤其要注意何时"事件触发.

随意将 DataGridView 和多行 TextBox 拖放到新的winforms Form 上,如上所示.然后使用下面的代码,可能会有助于遵循以下内容.

首先,要注意的是网格 UserAddedRow 事件何时触发?如果将选定的单元格移到新行,或者单击到新行中的单元格,则什么也没有发生…… UserAddedRow 事件不会触发.

但是,如果选定的单元格是新"行中的单元格……而用户"在该单元格中键入了一个字符,则将触发 UserAddedRow 网格.您应该注意一些其他行为.

要注意的一件事是,只要用户在新的行单元格中键入一个字符,表格"ADD"就会在另一个新"行中显示.

要注意的另一重要事项是,当该事件触发"时,用户仅在单元格中键入了一个字符.如果用户继续在该单元格中键入其他字符或移至新"行中的另一个单元格并开始键入文本,则 UserAddedRow 事件不会重新触发.

鉴于此,应该看起来很清楚,尝试从 UserAddedRow 事件的"new"行中抢夺"任何单元格值是行不通的.我们最希望得到的是用户键入的第一个字符.

因此,这里有一个难题.我们想获取这些值,但是我们需要在用户输入完文本后之后"获取它们.换句话说,我们希望在用户完成"时获取值.但是,有多种方法可以执行此操作,无论我们选择哪个事件来获取值……这些事件都不会知道这是否是"NEW"行.

因此,一种解决方案是创建一个全局变量……我们将其称为 LastNewRowIndex .最初,它将设置为-1,以指示尚未创建新"行.然后,我们可以将此变量设置为新添加"行的行索引.网格 UserAddedRow 事件将"为此工作.在这种情况下,无需尝试获取值,只需将此 LastNewRowIndex 变量设置为新的行索引,然后退出并等待",直到用户完成操作为止.

该事件可能如下所示.注意(-1)… e.Row.Index 将指向刚刚"添加的新行,该行将位于用户所在行的正下方.这是因为一旦用户在(当前)新"行单元格中键入了一个字符,网格就会添加另一个新"行,并成为新"行.因此,我们将知道自从在触发此事件之前添加了一行,至少会有一行.

  private void dataGridView1_UserAddedRow(对象发送者,DataGridViewRowEventArgs e){LastNewRowIndex = e.Row.Index -1;} 

现在,当我们要检查单元格值的事件时,我们可以通过检查 LastNewRowIndex 变量来检查它是否是"new"行中的一个单元格.如果它是-1,则它不是新行.如果它是大于-1的正数,则该数字将是用户在新行的单元格中键入一些文本之前之前"是新行的网格中的行".

所以,下一个问题是……我要使用哪个事件来获取这些值?显然,有许多不同的方法.恕我直言,一个可能和另一个一样好.

按照前面的示例,用户在新的行单元格零中键入一些文本.触发 UserAddedRow 事件,我们捕获了新的行索引.用户单击或导航到另一个单元格后,我们便可以使用网格 CellValueChanged 事件捕获值,因为它已更改.然后,我们可以检查 LastNewRowIndex 是否大于-1,以确定此单元格是否在新行中.

使用网格, CellValueChanged 事件具有一些缺点,但是,在某些情况下可能会很好地起作用.恕我直言,如果这是新行…那么我真的不在乎新行的单元格值是否发生变化.

我真正关心的是,用户何时尝试离开""NEW"行.

一旦用户单击或导航到不在新行中的任何单元格,那么我想从新行中收集这些值.换句话说,如果用户单击同一新"行中的另一个单元格,我不会在意这些单元格的值.

允许用户未完成在新行的所有单元格中键入文本的操作,并且可能使某些单元格为空.这是一个不同的故事,不在本示例的讨论范围之内.如果您想确保新行中的所有单元格都已填写,那么在我在下面使用的情况下,您也可以进行检查.

考虑到我们需要等待"直到用户完成向所有(或某些)新"行单元格中添加文本,我将假设用户在尝试离开"新行时完成".为此,我将使用网格 RowLeave 事件在用户离开"新行时捕获单元格值.

首先检查 LastNewRowIndex 是否大于-1.如果是,则我们知道用户正在离开"新添加的行,并且用户已在一个单元格中键入了至少一个字符,但也可能已将其删除.不能保证所有单元格值都已设置.它们可能全部为空或为空.您可以在这里检查是否所有单元格中都设置了所有值,如果需要某些值,则可以执行一些操作.

此外,网格的 RowLeave 事件可能在提交最后一个单元格之前触发".意味着最后编辑的单元格可能包含先前的值,而不是当前值.由于我们知道"用户正在离开"当前行,因此我们可以继续进行这些更改.如果您不提交更改,则新行上的最后编辑的单元格可能不包含新的编辑"值.

在下面的示例中,右侧的文本框显示两个事件的值.完成示例的其他代码.

  DataTable GridTable;int LastNewRowIndex = -1;公开Form1(){InitializeComponent();}私人void Form1_Load(object sender,EventArgs e){GridTable = GetDT();dataGridView1.DataSource = GridTable;}私有数据表GetDT(){DataTable dt = new DataTable();dt.Columns.Add("Col0&",typeof(string));dt.Columns.Add("Col1",typeof(string));dt.Columns.Add("Col2",typeof(string));for(int i = 0; i< 5; i ++){dt.Rows.Add("C0R" + i,"C1R" + i,"C2R" + i);}返回dt}私人void dataGridView1_UserAddedRow(对象发送者,DataGridViewRowEventArgs e){LastNewRowIndex = e.Row.Index -1;//<-我们知道至少有一行,因为它刚刚被添加了textBox1.Text + =在行索引处编辑新行"+ LastNewRowIndex + Environment.NewLine;}私有void dataGridView1_RowLeave(对象发送者,DataGridViewCellEventArgs e){如果(LastNewRowIndex> -1){dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);textBox1.Text + =在索引处保留新行"+ LastNewRowIndex +"低于"的单元格值+ Environment.NewLine;DataGridViewRow dgvR = dataGridView1.Rows [LastNewRowIndex];foreach(dgvR.Cells中的DataGridViewCell单元){textBox1.Text + ="cell [";+ cell.ColumnIndex +] =";如果(string.IsNullOrEmpty(cell.Value.ToString())){textBox1.Text + ="null or empty";}别的 {textBox1.Text + = cell.Value;}textBox1.Text + = Environment.NewLine;}LastNewRowIndex = -1;}别的 {//未设置新行}} 

I would like to get value from row after a user added some row.

I have seen this issue Getting user added row in DataGridView I have tried different DataGridView events: UserAddedRow, RowsAdded, RowValidated, RowPrePaint and etc. Everything works wrong.

private void sheetDataGridView_UserAddedRow(object sender, DataGridViewRowEventArgs e)
{
    Console.WriteLine(e.Row.Cells[0].Value);
}

解决方案

Being specific, obviously the grids AllowUserToAddRow is set to true and the underlying data source allows the user to add new rows. This new row in the grid is always placed at the bottom of the grid with obviously "empty" cells. Below is a grid that shows this "new" row.

You state that you want to get the values of the data from a cell when the user "adds" some value into one of the cells in the "new row." Specifically, from your posted code, it appears you want the data from the "new row" at cell zero (0).

This is doable, however as noted in the comments and your current dilemma, you need to be careful "which" events you use and more specifically, what to "DO" when the event fires, paying particular attention to "WHEN" the event fires.

Feel free to drop a DataGridView and a multiline TextBox onto a new winforms Form as show above. Then using the code below, it may help to follow what is described below.

First, to note is "WHEN" does the grids UserAddedRow event fire? If you move the selected cell to the new row OR if you click into a cell in the new row… nothing happens… the UserAddedRow event does NOT fire.

However, if the selected cell is a cell in the "new" row… AND the "user" types a single character into the cell… THEN the grids UserAddedRow fires. You should note some additional behavior.

One thing to notice is that as soon as the user types a character into the new row cell… the grid "ADDs" another "new" row.

Another important thing to note is that "when" this event fires, the user has ONLY typed a single character into the cell. If the user continues to type additional characters into that cell or moves to another cell in the "new" row and starts typing text… the UserAddedRow event does NOT refire.

Given this, it should appear clear, that trying to "grab" any of the cell values from the "new" row in the UserAddedRow event is not going to work. The best we could hope for is the first character typed by the user.

So herein lies a quandary. We want to get those values, but we need to get them "after" the user is done typing in the text. In other words, we want to get the values when the user is "done." There are numerous ways to do this, however, whichever event(s) we choose to get the values… those events are NOT going to know if this is the "NEW" row.

Therefore, one solution is to make a global variable… we will call it LastNewRowIndex. Initially it will be set to -1 to indicate that a "new" row has not been created yet. Then we can set this variable to the row index of the "newly" added row. The grids UserAddedRow event "will" work for this. In the event, instead of trying to grab the values, simply set this LastNewRowIndex variable to the new rows index, then exit and "wait" until the user has finished.

The event may look like below. Note the (-1)… the e.Row.Index is going to point to the "just" added new row which will be the row just below the row the user is on. This is because as soon as the user typed a character into the (current) "new" row cell… the grid adds another "new" row and it becomes the "new" row. Because of this, we will KNOW that there will be at least ONE row since one was added before this event was fired.

private void dataGridView1_UserAddedRow(object sender, DataGridViewRowEventArgs e) {
  LastNewRowIndex = e.Row.Index -1;
}

Now, when we get to the event where we want to check the cell values, we can check if it is a cell from the "new" row by checking the LastNewRowIndex variable. If it is -1, then it is not a new row. If it is any positive number greater than -1, then that number will be the "row" in the grid that "was" the new row "before" the user typed some text into a cell in the new row.

So, the next question is… which event do I use to get those values? Obviously, there are many different ways to go. And IMHO, one is probably just as good as the other.

Following our previous example, the user types some text into the new row cell zero. The UserAddedRow event fires and we capture the new row index. As soon as the user, clicks or navigates to another cell, then we could use the grids CellValueChanged event to capture the value since it has changed. We could then check to see if LastNewRowIndex is greater than -1 to determine if this cell IS in the new row.

Using the grids, CellValueChanged event has some drawbacks, however, it may well work for some cases. IMHO, if this is a NEW row… then I really do not care if a new row’s cell value changes.

Is what I DO care about and want to know is "WHEN" the user tries to "LEAVE" the "NEW" row.

As soon as the user clicks or navigates to any cell that is NOT in the new row, THEN I want to collect those values from the new row. In other words, I do not care about the cells values if the user clicked on another cell in the same "new" row.

Granted the user may not have finished typing text into all the cells in the new row and may leave some cells null. This is a different story and is outside the scope of this example. If you wanted to make sure ALL the cells on the new row are filled in, then you could also check this in the event I use below.

Considering we need to "wait" until the user finishes adding text to all (or some) of the "new" row cells, I will assume the user is "done" when the user tries to "leave" that new row. For this I will use the grids RowLeave event to capture the cell values when the user "leaves" the new row.

First a check is made to see if LastNewRowIndex is greater than -1. If it is, then we know that the user is "leaving" the newly added row and the user has typed at least one character into one of the cells, but may have removed it also. There are no guarantees that all cell values are set. They may all well be empty or null. This may be one place where you could check to see if all the values are set in all the cells and do something if certain values are required.

Also, The grid’s RowLeave event may fire "before" the last cells edit was committed. Meaning that the last edited cell may contain the previous value and not the current value. Since we "know" that the user is "leaving" the current row, we can go ahead and commit those changes. If you do not commit the changes, then the last edited cell on the new row may not contain the newly "edited" value.

In the example below, the text box on the right display the values of both events. Additional code to complete the example.

DataTable GridTable;
int LastNewRowIndex = -1;

public Form1() {
  InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e) {
  GridTable = GetDT();
  dataGridView1.DataSource = GridTable;
}

private DataTable GetDT() {
  DataTable dt = new DataTable();
  dt.Columns.Add("Col0", typeof(string));
  dt.Columns.Add("Col1", typeof(string));
  dt.Columns.Add("Col2", typeof(string));
  for (int i = 0; i < 5; i++) {
    dt.Rows.Add("C0R" + i, "C1R" + i, "C2R" + i);
  }
  return dt;
}

private void dataGridView1_UserAddedRow(object sender, DataGridViewRowEventArgs e) {
  LastNewRowIndex = e.Row.Index -1; // <- We KNOW that there is at least ONE row because it was just added
  textBox1.Text += "New row being editied at row index " + LastNewRowIndex + Environment.NewLine;
}

private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e) {
  if (LastNewRowIndex > -1) {
    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    textBox1.Text += "Leaving new row at index " + LastNewRowIndex + " cell values below" + Environment.NewLine;
    DataGridViewRow dgvR = dataGridView1.Rows[LastNewRowIndex];
    foreach (DataGridViewCell cell in dgvR.Cells) {
      textBox1.Text += "cell[" + cell.ColumnIndex + "]= ";
      if (string.IsNullOrEmpty(cell.Value.ToString())) {
        textBox1.Text += "null or empty";
      }
      else {
        textBox1.Text += cell.Value;
      }
      textBox1.Text += Environment.NewLine;
    }
    LastNewRowIndex = -1;
  }
  else {
    // new row not set
  }
}

这篇关于从DataGridView中用户添加的行中获取值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆