Instead of writing validation code into the
CellValidating event of the
DataGridView control is better to implement a validation system based on the
IDataErrorInfo interface.
The UI with the ErrorProvider icon:

At the and the class to be validated looks like this:
public class Customer
: Validable<Customer>
{
public string Name { get; set; }
public int Age { get; set; }
}
An example of a validation class:
public class CustomerValidator
: Validator<Customer>
{
public override string Validate(Customer obj, string propertyName)
{
if (propertyName == Property(x => x.Name))
{
return string.IsNullOrWhiteSpace(obj.Name) ? "Must be not empty." : null;
}
if (propertyName == Property(x => x.Age))
{
if (obj.Age < 18)
{
return "Age must be greather than 18.";
}
}
return ValidateOnStorage(obj);
}
private string ValidateOnStorage(Customer obj)
{
var customerRepository =
DependencyResolver
.Resolve<CustomerRepository>();
if (customerRepository.GetAll().Any(c => c.Name == obj.Name))
{
return string.Format("Customer with name {0} already exists.", obj.Name);
}
return null;
}
}
And the base class:
public abstract class Validator<T> :
IValidator<T> where T : class
{
public abstract string Validate(T obj, string propertyName);
public string Validate(object obj, string propertyName)
{
return Validate((T)obj, propertyName);
}
/// <exception cref="ArgumentException">The given expression is not a MemberExpression.</exception>
protected string Property<TProperty>(Expression<Func<T, TProperty>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
{
throw new ArgumentException("The given expression is not a MemberExpression.", "expression");
}
var propertyInfo =
memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException("The given expression is not a property.", "expression");
}
return propertyInfo.Name;
}
}