NoNullAllowedException
Hello, I recently setup my DataGridView to use the RowValidating event. However, whenever a user types something in to a NewRow (as to cause the DGV to create a new row and consider the current row's NewRow = false) and then hit escape to cancel the edit, the DataError exception goes nuts. It keeps spitting out "Index 4 does not exist" in what seems to be an infinite loop.
Here is my RowValidating code:
| | privatevoid dgvMain_RowValidating(object sender, DataGridViewCellCancelEventArgs e) { if (dgvMain.Rows[e.RowIndex] !=null && !dgvMain.Rows[e.RowIndex].IsNewRow) { stringerror = "";if (dgvMain.Rows[e.RowIndex].Cells["CDS"].Value ==null || dgvMain.Rows[e.RowIndex].Cells["CDS"].Value.ToString().Trim() == "") error += " * Site\n"; if (dgvMain.Rows[e.RowIndex].Cells["FirstName"].Value ==null || dgvMain.Rows[e.RowIndex].Cells["FirstName"].Value.ToString().Trim() == "") error += " * First Name\n"; if (dgvMain.Rows[e.RowIndex].Cells["LastName"].Value ==null || dgvMain.Rows[e.RowIndex].Cells["LastName"].Value.ToString().Trim() == "") error += " * Last Name\n"; if (dgvMain.Rows[e.RowIndex].Cells["Email"].Value ==null || dgvMain.Rows[e.RowIndex].Cells["Email"].Value.ToString().Trim() == "") error += " * Email\n"; if (error != "") { MessageBox.Show("The following required fields were left blank:\n\n" +error, "Row Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Error); e.Cancel =true; } } }
|
Note: I have determined that any access to dgvMain.Rows[e.RowIndex] (EVEN TO CHECK IF ITS NULL) will cause the dataerror to go nuts when hitting the escape key. If I comment out any part that access dgvMain.Rows[e.RowIndex] in the RowValidating event, it works fine (but obviously doesn't validate like it should).
Also, if I try to Watch anything in the debugger, it says the DGV has 6 rows (it should have had 6 before, 5 after you hit escape and cancel the edit). If I try to Watch dgvMain.Rows[4] it times out and then my debugging doesnt work anymore after that, but if I try to view any other row it works fine. This kind of seems like a bug in the framework, but I'm really not too sure. By the way, I'm using VS2005/.NET RC.
Is there anyway I can get this to work, or to disable the ability to cancel editing with the Escape key?
Thanks
-Adam
Does anyone know how I can work around this? This is a pretty big issue. The end-users are losing their data (if they don't commit it) whenever they hit escape because it's causing them to have to kill the program. I need to validate the rows, but it seems that removing the RowValidating event is the only way to fix this.. PLEASE HELP

TIA
-Adam
I tried this out on the RTM version and didn't have any problems. Can you provide the actual steps that you used? I did this:
1) New WF app
2) Add a DGV and create 4 columns named CDS, FirstName, LastName & Email
3) Handle the RowValidating event and add the above code to it
4) Run
5) Type a value in the first cell (cause the DGV to create a new row and consider the current row's NewRow = false)
6) Hit ESC
7) Row is removed
8) Type a value in the first cell (same as 5)
9) Hit the down arrow or click out of the grid
10) Messsagebox from RowValidating event is shown.Is this what you are seeing?
-mark
DataGridView Program manager
Microsoft
This post is provided "as-is"
Hi Mark, I'm trying my hardest to reproduce this problem in a test app but I can't. I have narrowed down the problem on my existing app though. On my main app, if I press escape it fires the RowValidating event - and the exact line of code that is causing the problem is the MessageBox.Show() method (if I comment out that one line, it works fine).
Here's the weird (or weirder) part though: on my test app, the RowValidating event never gets fired if you press escape to cancel the edit - which seems right. For some reason, my main app does fire that event. Mark, do you know what could cause a RowValidating event to fire? I have removed ALL other datagrid events except for RowValidating - and it's that one stupid messagebox that's actually the causing the problem within that event.
I will continue to try to find the answer for this and attempt to reproduce it in a test app if I can.
Thanks a lot
-Adam
Hi Mark, I was able to reproduce the problem in a simple test app.
First, it will have to be a data-driven DataGridView, my example uses the northwind database (although you will need to modify the connection string).
Create a blank Winforms project and drag a DataGridView control to the form.
In the forms Load event add the following code:
| |
DataTable tempData = new DataTable(); SqlConnection con = new SqlConnection("Persist Security Info=True;User ID=****;Password=****;Initial Catalog=NorthWind;Data Source=****"); SqlDataAdapter da = new SqlDataAdapter(new SqlCommand("SELECT * FROM Customers", con)); da.Fill(tempData); dataGridView1.DataSource = tempData;
|
Now, create a RowValidating event handler for the DGV with the following code:
| |
private void dataGridView1_RowValidating(object sender, DataGridViewCellCancelEventArgs e) { if (dataGridView1.Rows[e.RowIndex] != null && !dataGridView1.Rows[e.RowIndex].IsNewRow) { string error = ""; if (dataGridView1.Rows[e.RowIndex].Cells["CompanyName"].Value == null || dataGridView1.Rows[e.RowIndex].Cells["CompanyName"].Value.ToString().Trim() == "") error += " * Company Name\n"; if (dataGridView1.Rows[e.RowIndex].Cells["ContactName"].Value == null || dataGridView1.Rows[e.RowIndex].Cells["ContactName"].Value.ToString().Trim() == "") error += " * Contact Name\n"; if (error != "") { MessageBox.Show("The following required fields were left blank:\n\n" + error, "Row Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Error); e.Cancel = true; } } }
|
Note: I also added the System.Data.SqlClient namespace.
If you run this app and try to enter data into a new row and press escape, it should generate a bunch of errors (via the DataError event). If you catch those errors, it will give you the index out of range errors.
Thanks
-Adam
This is correct behavior, but kinda weird the way it comes across. The issue is that when you press Esc the row is actually removed already since you are escaping out of the cell edit. Since the edit in the cell was the only thing that was keeping the row from being around the row is in the process of being removed. This isn't something that can be canceled (the removal of the row), but since focus is being moved to the next row, the RowValidating event is fired.
Anyway, displaying the MessageBox causes problems in this case because it "pauses" the processing of the row removal. In this paused state the row does not exist in the database view, so when we try to paint the row (as a result of the messagebox) we find that the row doesn't exist, so we raise the DataError event
The only thing you need to add to your code is a check to see if the row you are validating is dirty:
| | if (dataGridView1.Rows[e.RowIndex] != null && !dataGridView1.Rows[e.RowIndex].IsNewRow && dataGridView1.IsCurrentRowDirty) |
Hope this helps,
-mark
DataGridView Program Manager
Microsoft
Mark.. you rock, thanks so much, that helped a lot. I implemented it on several of my grids and it fixed that problem on all of them. A few of them are now giving me a "Current cell cannot be set to an invisible cell" exception, but I haven't yet taken the time to debug it and I don't think I'll have any problem fixing that.
Thanks again
Mark, I got one more scenario that I would like to run by you to see if you can help. Using the test code that I provided before, try changing the query to do a "SELECT TOP 0 * FROM Customers" as to create a databound DataGridView - only with 0 records.
Now try to edit a cell on the first row and press escape - everything works fine, the extra row goes away...
But if you try to edit a cell on the first row, then switch to another cell (on the same row) and begin editting it, now press escape twice - it creates an extra row. This doesn't seem to have anything to do with the RowValidating event. If I comment it out, it still behaves oddly.
Do you know of a fix for this behavior? At least it's not throwing a bunch of exceptions, but it would still be nice if there's a fix for this (so I don't have a few null rows added to my DB).
Thanks again.
-Adam
I'm having the same errors!
I'm having some trouble with my DataGridView object.
Here's what I've got:
1) A table with columns int pk PRIMARY KEY AUTOINCREMENT, nvarchar(16) cod NOT NULL, nvarchar(60) desc NOT NULL, int a, int b, int c.
2) A DataGridView bound to that table through a DataSet. The pk column is not show nor hidden.
I'm trying to error handle all faults caused by bad filled rows. I've already read the posts about the RowValidating and CellValidating events and they worked just fine.
Except...
I'm testing the DataGridView to ensure that all the ways of filling a row will be validated and will not raise any unhandled error.
But I've found some disturbing error: everytime I fill the initial column cod (it's marked as NOT NULL) and move to another column without filling nor editing it (it's just selected), if I press the ESCAPE key it raises an error through it's CancelEdit method, telling me that's it's not possible for the cod column to be NULL. Too bad the error closes the form.
I wonder if you could help me to handle such error.
Thanks a lot!
Jos Carlos Júnior.
Does anyone know how to fix this? Thanks
No. This is a known bug in the grid. We have not found a workaround yet.
-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"
Hello Adam and Mark,
I came across this problem and fixed it in my application by overriding the OnKeyDown event on the DataGridView. And making sure the BindingSource.CancelEdit() method is called instead of the dataGridView.CancelEdit() which it seems to me ends up calling EndEdit() somewhere down the line.
private void dataGridView1_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.Escape) {
dataGridView1BindingSource.CancelEdit();
e.Handled = true;
}
else { base.OnKeyDown(e); }
}
Good looking out Erik, I will try this on Tuesday (when I'm back at work). Thanks a lot
Handling the KeyDown event or indeed any other event that takes place doesn't work for me. I can see the events being handled when I am on rows 2, 3, 4, etc but when I am on row 1, raise the DataError event of the dgv and then press escape there seems to be no way to stop the whole app bombing! (I am using VB.NET not C#)
I have tried all sorts of ways to intercept the exception but all of the exposed events are just ignored as far as I can see. Does anyone else have a workaround please? Any service packs due out soon? The dgv is unusable for me at the moment.
Yes, I had prevented this bug with the same quick-method (handling keydown event of the datagridview ) but it's getting harder for me to stand all these unsolved bugs. I think I will go on with Java as I did before and offer you all to do the same :)