Reputation: 20997
I have WinForms DataGridView
with source set to SortableBindingList
. In this form, there's column Comment
and I need to prevent user from inserting some characters, thus validation.
What I want to do is, whenever user enters invalid value, system will notify him (OnNotification( 'You entered wrong comment');
) and force him/her to stay in edit mode.
So far I build solution like this:
void MyDataGridView_CellEndEdit( object sender, DataGridViewCellEventArgs e )
{
if (e.ColumnIndex == ColumnComment.Index) {
object data = Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
if( (data != null) && (!CommentIsValid( data.ToString()))){
CurrentCell = Rows[e.RowIndex].Cells[e.ColumnIndex];
BeginEdit( true );
// My notification method
OnNotification( String.Format( "Comment `{0}` contains invalid characters) );
return;
}
}
}
I have following issues with this:
OnCellValidating
is triggered only when whole form is closing or when current row is changed, not after I finish editing of single cell, so I've put check into CellEndEdit
.Enter
/Esc
to end editing, it works as expected and desired.Enter
(displays notification on invalid comment) and then Esc
(to cancel edit) it uses value pushed by Enter
(because edit mode has finished).So my questions are:
CellValidating
after each cell edit, not when form is closingCurrentRow
and CurrentCell
change even after mouse click?Upvotes: 2
Views: 11110
Reputation: 421
Unfortunately, MoonKnight's solution didn't work fully for me as the code in CellContentClick
event handler never set the control back to the cell that was being validated for its value, when it had an invalid value. Nevertheless, considering his valuable hint of using global variables isInvalidState
and invalidCell
helped me constructing the following solution that works exactly as asked in the OP.
Using the combination of CellValidating
and CellValidated
in the right way solves the problem as follows:
Do your data validation inside the CellValidating
event handler. Set the isInvalidState
flag and the cellWithInvalidUserInput
variable (NOTE: I renamed the invalidCell
to cellWithInvalidUserInput
):
private void MyDataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
var cellUnderConsideration = MyDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex];
if (!ValidateCurrentCellValue(cellUnderConsideration))
{
OnNotification( String.Format( "Comment `{0}` contains invalid characters) );
//Or MessageBox.Show("your custom message");
isInvalidState = true;
cellWithInvalidUserInput = cellUnderConsideration;
e.Cancel = true;
}
}
The data validation function:
bool isInvalidState;
DataGridViewCell cellWithInvalidUserInput;
private bool ValidateCurrentCellValue(DataGridViewCell cellToBeValidated)
{
//return 'true' if valid, 'false' otherwise
}
Perform desired actions on UI controls inside the CellValidated
event handler:
private void MyDataGridView_CellValidated(object sender, DataGridViewCellEventArgs e)
{
if (isInvalidState)
{
isInvalidState = false;
if (cellWithInvalidUserInput != null && cellWithInvalidUserInput.RowIndex > -1)
{
MyDataGridView.CurrentCell = cellWithInvalidUserInput;
MyDataGridView.CurrentCell.Selected = true;
MyDataGridView.BeginEdit(true);
}
cellWithInvalidUserInput = null;
}
}
Upvotes: 0
Reputation: 23833
When I use mouse and click to another row, cell stays in edit mode, but another row gets selected.
Here I would use a global Boolean, bool isInvalidState
say and a global DataGridViewCell = invalidCell
object. In the default state you can set isInvalidState = false
and invalidCell = null
. Then using
private bool OnNotification(string cellValue)
{
// Check for error.
if (error)
return false;
}
Then in the above method
void MyDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == ColumnComment.Index) {
object data = Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
if((data != null) && (!CommentIsValid(data.ToString()))){
CurrentCell = Rows[e.RowIndex].Cells[e.ColumnIndex];
BeginEdit(true);
// My notification method
isInvalidState = OnNotification(
String.Format("Comment `{0}` contains invalid characters));
if (isInvalidState)
invalidCell = MyDataGridView[e.RowIndex, e.ColumnIndex];
return;
}
}
}
Now, wire-up an event CellContentClick
on your DataGridView
and check if isInvalidState == true
private void MyDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (isInvlaidState)
{
isInvalidState = false;
MyDataGridView.CurrentCell = invalidCell;
invalidCell = null;
return;
}
// Do other stuff here.
}
When I try to use Enter (displays notification on invalid comment) and then Esc (to cancel edit) it uses value pushed by Enter (because edit mode has finished).
I am not sure about this problem; it is likely you will have to handle the KeyDown
event and capture the escape key - handling it differently.
I hope this helps.
Upvotes: 1
Reputation: 92
Try something like this. It shall work.
private void datagridview1_dataGridview_CellValidating
(object sender, DataGridViewCellValidatingEventArgs e)
{
if (datagridview1_dataGridview.Rows[e.RowIndex].Cells[2].Value.Equals(""))
{
MessageBox.Show("Product name should not be empty", "Error");
datagridview1_dataGridview.CurrentCell = datagridview1_dataGridview.Rows[e.RowIndex].Cells[2];
datagridview1_dataGridview.CurrentCell.Selected = true;
}
}
Upvotes: 0