Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataGridView DataError Event Preserve invalid row

I am working on a Winforms app that displays a DataGridView, bound to some database table.

It allows inserting fresh entries in to it, and does some data validation.

When a required column is left blank, or one of the unique constraints is violated, the DataError event calls this function:

protected void _data_error(object sender, DataGridViewDataErrorEventArgs e)
{
    MessageBox.Show(this,e.Exception.Message,"Error");
    e.ThrowException = false;
    e.Cancel = false;
}

When the popup is closed, the new row that was being edited is removed.
When this is done to a row that has already been saved (an update operation) the row loses its changes and loses focus. I assume this means I need to signal the application to keep the row editable, but I do not know how to do that.

Paradoxically, if I replace the event handler with a throw(e.Exception) the exception gets thrown to the wind and is picked up by the uncaught exception handler, but the new row is preserved after that window closes.

How can I preserve the new row on a DataError event?

Edit:

My next thought was to save the row and add it to the DataGridView's data source after the MessageBox pops up. That does not work because adding data to the data source add's it as a committed row which throws an exception because of the invalid data vs keeping the data as an editable row so that validation doesn't happen.

like image 790
Chris Avatar asked Nov 21 '12 14:11

Chris


2 Answers

Took me a few days but here is how I fixed it, but I am still open for a better way.

In the DataGridView.RowValidating event, validate the contents of each cell. If it is invalid do this:

Grid.Rows[e.RowIndex].ErrorText = "Concisely describe the error and how to fix it";
e.Cancel = true;

And make sure you clear out the error text on the next trip through the event handler.

For the case when a user is entering an invalid type of data, text into a numerical only column for instance, you will have to handle the error in a DataGridView.DataError event. Use the same code:

Grid.Rows[e.RowIndex].ErrorText...

but there is no need to clear the ErrorText as your row validation event will handle that.

Note: This will not allow you to have popups to inform the user what is wrong, it will use the DataGridView error, which is a red exclamation mark on the left hand side of the grid that has mouseover text displaying the ErrorText you filled. It appears anytime you have a MessageBox popup you will lose focus on the editable data and lose the row.

like image 164
Chris Avatar answered Nov 08 '22 05:11

Chris


From MSDN

private void DataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs anError)
{
MessageBox.Show(anError.RowIndex + " " + anError.ColumnIndex);
MessageBox.Show("Error happened " + anError.Context.ToString());

if (anError.Context == DataGridViewDataErrorContexts.Commit)
{
    MessageBox.Show("Commit error");
}
if (anError.Context == DataGridViewDataErrorContexts.CurrentCellChange)
{
    MessageBox.Show("Cell change");
}
if (anError.Context == DataGridViewDataErrorContexts.Parsing)
{
    MessageBox.Show("parsing error");
}
if (anError.Context == DataGridViewDataErrorContexts.LeaveControl)
{
    MessageBox.Show("leave control error");
}

if ((anError.Exception) is ConstraintException)
{
    DataGridView view = (DataGridView)sender;
    view.Rows[anError.RowIndex].ErrorText = "an error";
    view.Rows[anError.RowIndex].Cells[anError.ColumnIndex].ErrorText = "an error";

    anError.ThrowException = false;
}
}
like image 32
ISCI Avatar answered Nov 08 '22 06:11

ISCI