问题
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