my goal is to have a friendly validation flow on my DataGridView.
When the user enters an incorrect value for a certain cell, I want to:
exit editing mode
revert the modification (i.e. recover the original value from the cell)
display an error message
I am currently using the CellValidating event to prevent the cell from updating its value but I'm not able to exit the editing mode. The cell is then waiting for a correct value and won't let the user to simply cancel&revert his action...
Here is what the validation method looks like :
private void dataGridViewMsg_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
[...] // Here, treatment determines is the new cell value isValid or not
if (!isValid)
{
MessageBox.Show("The value entered is incorrect.", "Modification aborted");
e.Cancel = true;
dataGridViewMsg[e.ColumnIndex, e.RowIndex].IsInEditMode = false; // Someway, what I would like to do
return;
}
}
How can I proceed to make the cell recover its original value without requiring me to keep track of this value?
You can use EndEdit() to get what you want.
In any case, note that it is better to make sure that the cancellation happens only under the expected conditions; otherwise, the code might get stuck in this event because it is automatically called at many different points. For example, to validate the inputs written by the user via cell edition, you can rely on an approach on the lines of the following one:
bool cancelIt = false;
private void dataGridViewMsg_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
[...] // Here, treatment determines is the new cell value isValid or not
if (cancelIt && !isValid)
{
MessageBox.Show("The value entered is incorrect.", "Modification aborted");
e.Cancel = true;
dataGridViewMsg.EndEdit();
cancelIt = false;
}
}
//CellBeginEdit event -> the user has edited the cell and the cancellation part
//can be executed without any problem
private void dataGridViewMsg_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
cancelIt = true;
}
Related
I want to cancel a DataGridView cell edit when validating a wrong value similar to what happens when the user presses Esc.
My code like below but its behavior still different from pressing Esc.
private void dgvSPS_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
if (e.ColumnIndex == 0)
{
dgv.CurrentCell.Value = string.Empty;
e.Cancel = true;
dgv.EndEdit()
return;
}
}
I want behavior when validating is wrong like pressing Esc.
clear current cell
remove new line (if current cell is new line)
current cell focus to last row cell
You can use the CancelEdit() method:
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
// Just an example for a "wrong value".
bool someCondition = (e.FormattedValue.ToString() == "c");
if (someCondition)
{
dgv.CancelEdit();
}
}
Note that for requirement #3, this will only return the focus to the cell that was being edited if it's a new row. If that's not good enough and you want to focus the previous cell no matter what, you may add e.Cancel = true; and dgv.EndEdit(); back in the if block:
if (someCondition)
{
dgv.CancelEdit(); // Discards changes.
e.Cancel = true; // Forces the focus to remain in the current cell.
dgv.EndEdit(); // Exit the editing control which is still active
// because of e.Cancel.
}
I am writing a C# application that uses a DataGridView and I would like to validate the input each time a user changes the data that's there.
I began by using the CellValidating event which has a really nice CancelEdit() method that will return the cell to its previous value. However, this event is fired every time the user leaves the cell, regardless of whether or not it has changed.
Does CellValueChanged support a sort of cancel or rollback method to the previous value? This way I would be able to still validate the data, but not waste time with cells that didn't need it, but would prefer not to sacrifice the ability to restore the cell if data is invalid.
Here is a bit of code:
private void dataGrid1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if(dataGrid1.Columns[e.ColumnIndex].Name == "dateColumn")
{
String input = e.FormattedValue.ToString();
// Split the date from MM/DD/YYYY format
String[] temps = input.Split('/');
try
{
if(temps[2].Length != 4)
MessageBox.Show("The year entered is not the correct length.", "Invalid Year", MessageBoxButtons.OK);
DateTime date = new DateTime(Convert.ToInt32(temps[2]), Convert.ToInt32(temps[0]), Convert.ToInt32(temps[1]));
}
catch (Exception ex) // If exception is thrown, date was invalid
{
MessageBox.Show("The date entered was invalid.", "Invalid date", MessageBoxButtons.OK);
dataGrid1.CancelEdit(); // Set cell value back to what it was prior to user's change
e.Cancel = true; // Have focus stays with this cell rather than move down a row.
}
}
}
You could try another aproach like this:
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
newvalue = (int)dataGridView1[e.ColumnIndex, e.RowIndex].Value;
}
private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
oldvalue = (int)dataGridView1[e.ColumnIndex, e.RowIndex].Value;
}
Assuming its an int,if its another datatype then will also work(except offcourse the variables oldvalue and newvalue must be that type also).
Or by your question,its just about the old value,then you will only need the CellBeginEdit event and then use the oldvalue variable inside the validating event.
IMHO better solution, cause underlying DataTable will not be marked as changed if you reject the value. Old value will be displayed automatically
private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
var underlyingDataRow = ((DataRowView)dataGridView.Rows[e.RowIndex].DataBoundItem).Row;
if (DoesNotMeetYourCondition)
{
row.RejectChanges();
}
I am having a bit of an issue with the datagridview's CellEndEdit event. While I understand the concept of what the issue actually is, any attempt at circumventing it seems to fail.
Basically, I have a datagridview, in the CellEndEdit event, I make a check against the database to make sure the entry is not a duplicate. If it is, I prompt the user with a messagebox to tell them they can't enter duplicates, I then change the value back to its original state/value programmatically, and return the cell to an "Edit" state.
My understanding is that the fact that i'm changing the value programatically is why the event fires twice. To circumvent, I set a flag upon first entering the event, then prompt + set + re-edit, then set the flag to false. This does not work... can anyone tell me why or how I can make this happen?
Here's the event code:
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
if(e.ColumnIndex == this.dataGridView1.Columns["Name"].ColumnIndex)
{
if(!this.CellBeingEdited)
{
string NewName = this.dataGridView1.Rows[e.RowIndex].Cells["Name"].Value.ToString();
//-== DATABASE CODE REMOVED ==-
bool IsDuplicate = ...;
if(IsDuplicate)
{
MessageBox.Show("Cannot have duplicate item names at this level!");
this.dataGridView1.CurrentCell = this.dataGridView1.Rows[e.RowIndex].Cells["Name"];
this.CellBeingEdited = true;
this.dataGridView1.CurrentCell.Value = this.LastEditedRowName;
this.CellBeingEdited = false;
this.dataGridView1.BeginEdit(false);
return;
}
}
}
}
This bit of code does not fire twice when I edit a value in a row :
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
string test = "test";
if (this.dataGridView1.Rows[e.RowIndex].Cells[0].Value.ToString() == test)
{
this.dataGridView1.CurrentCell = this.dataGridView1.Rows[e.RowIndex].Cells[0];
this.dataGridView1.CurrentCell.Value = "not test";
this.dataGridView1.BeginEdit(false);
return;
}
}
Perhaps are you calling the event elsewhere?
I am writing a C# application that uses a DataGridView and I would like to validate the input each time a user changes the data that's there.
I began by using the CellValidating event which has a really nice CancelEdit() method that will return the cell to its previous value. However, this event is fired every time the user leaves the cell, regardless of whether or not it has changed.
Does CellValueChanged support a sort of cancel or rollback method to the previous value? This way I would be able to still validate the data, but not waste time with cells that didn't need it, but would prefer not to sacrifice the ability to restore the cell if data is invalid.
Here is a bit of code:
private void dataGrid1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if(dataGrid1.Columns[e.ColumnIndex].Name == "dateColumn")
{
String input = e.FormattedValue.ToString();
// Split the date from MM/DD/YYYY format
String[] temps = input.Split('/');
try
{
if(temps[2].Length != 4)
MessageBox.Show("The year entered is not the correct length.", "Invalid Year", MessageBoxButtons.OK);
DateTime date = new DateTime(Convert.ToInt32(temps[2]), Convert.ToInt32(temps[0]), Convert.ToInt32(temps[1]));
}
catch (Exception ex) // If exception is thrown, date was invalid
{
MessageBox.Show("The date entered was invalid.", "Invalid date", MessageBoxButtons.OK);
dataGrid1.CancelEdit(); // Set cell value back to what it was prior to user's change
e.Cancel = true; // Have focus stays with this cell rather than move down a row.
}
}
}
You could try another aproach like this:
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
newvalue = (int)dataGridView1[e.ColumnIndex, e.RowIndex].Value;
}
private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
oldvalue = (int)dataGridView1[e.ColumnIndex, e.RowIndex].Value;
}
Assuming its an int,if its another datatype then will also work(except offcourse the variables oldvalue and newvalue must be that type also).
Or by your question,its just about the old value,then you will only need the CellBeginEdit event and then use the oldvalue variable inside the validating event.
IMHO better solution, cause underlying DataTable will not be marked as changed if you reject the value. Old value will be displayed automatically
private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
var underlyingDataRow = ((DataRowView)dataGridView.Rows[e.RowIndex].DataBoundItem).Row;
if (DoesNotMeetYourCondition)
{
row.RejectChanges();
}
All, I want to catch the event after I finish input the value of DataGridView cell so that I can validate the value. Is there any event DataGridView when focus-lose happen? What is the best way to make it? thanks.
You should use CellValidating event for this, see here MSDN.
Occurs when a cell loses input focus, enabling content validation.
and example (from MSDN as well)
private void dataGridView1_CellValidating(object sender,
DataGridViewCellValidatingEventArgs e)
{
dataGridView1.Rows[e.RowIndex].ErrorText = "";
int newInteger;
// Don't try to validate the 'new row' until finished
// editing since there
// is not any point in validating its initial value.
if (dataGridView1.Rows[e.RowIndex].IsNewRow) { return; }
if (!int.TryParse(e.FormattedValue.ToString(),
out newInteger) || newInteger < 0)
{
e.Cancel = true;
dataGridView1.Rows[e.RowIndex].ErrorText = "the value must be a non-negative integer";
}
}