Getting values from user added row in DataGridView

此生再无相见时 提交于 2020-12-15 06:08:45

问题


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

回答1:


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


来源:https://stackoverflow.com/questions/64505932/getting-values-from-user-added-row-in-datagridview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!