开发者

Validation on Databoud DataGridView per Column

So I have a DataGridView which is used to display a list of custom models. Here is some sample code for a model:

public class TestModel
{
    public IEnumerable<string> GetValidationErrors()
    {
        if (Value1 > 100 || Value1 <= 0)
            yield return "Value1 can only be between 1 and 100 (inclusive)";

        if (string.IsNullOrEmpty(Value2))
            yield return "Value2 can not be empty";
    }

    public bool IsValid
    {
        get { return GetValidationErrors().Count() == 0; }
    }

    public int Value1
    {
        get; set;
    }

    public string Value2
    {
        get; set;
    }
}

Now let's say I was Binding a list (or IEnumerable) of these models like so

List<TestModel> list = Helpers.GetListOfTestModels();
dataGridView1.DataSource = list;

(We can assume that the list return is valid, or else it wouldn't be stored).

Now on the RowValidating event on the DataGridView, I can validate the entire row by accessing th开发者_StackOverflow社区e IsValid property and set a Rows[].ErrorText, like so:

private void dataGridView1_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
{
    var item = dataGridView1.Rows[e.RowIndex].DataBoundItem as TestModel;
    if (item == null)
        return;

    if(!item.IsValid)
    {
        dataGridView1.Rows[e.RowIndex].ErrorText = "Failed Validation"; // Or use GetValidationErrors and concat them, but to be simple I've left that out
        e.Cancel = true;
    }
    else
    {
        dataGridView1.Rows[e.RowIndex].ErrorText = string.Empty;
    }
}

Now, what I really want to do (without copying and pasting code all over the place), is validate each Property and set the Rows[].Cells[].ErrorText Property (this will show errors per cell, instead of the entire row).

How should I go about this?

Maybe something with Custom Attributes, then reflection to get the property name and access the cell that way?

Hopefully this all makes sense!


Solved it!

Have a abstract attribute like so:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public abstract class ValidationAttribute : Attribute
{
    public abstract void Validate(object value, PropertyInfo propertyInfo, ref IList<string> errors);
}

and an implementation like so:

public class ValidStringAttribute  : ValidationAttribute
{
    #region Overrides of ValidationAttribute

    public override void Validate(object value, PropertyInfo propertyInfo, ref IList<string> errors)
    {
        var v = propertyInfo.GetValue(value, null);

        if(!string.IsNullOrEmpty(v as string))
        {
            errors.Add(string.format("`{0}` cannot be null or empty",propertyInfo.Name);
        }
    }

    #endregion
}

Then Modify the Value2 Property like so:

[ValidString]
public string Value2
{ 
   get; set;
}

and in either the RowValidating or CellValidating Events do something like this:

if(!item.IsValid)
{
    foreach(var propertyInfo in item.GetType().GetProperties())
    {
        IList<string> list = new List<string>();
        foreach (ValidationAttribute attribute in propertyInfo.GetCustomAttributes(typeof(ValidationAttribute),true))
        {
            attribute.Validate(item,propertyInfo,ref list);
        }

        if(list.Count > 0)
        {
            // make sure it's not ignored
            var browsable = propertyInfo.GetCustomAttributes(typeof (BrowsableAttribute), true);
            if(browsable.Count() == 0)
            {
                dataGridView1.Rows[e.RowIndex].Cells[propertyInfo.Name].ErrorText = list[0];
            }
        }
    }

    e.Cancel = true;
}

and bam errors per property, with databinding!


Could you perhaps make use of the CellValidating event? This event fires similarly to the RowValidating except it occurs when you tab out of the cell.

Alternatively, if your row represents a Business Object, then you can expose a Validate method that will perform validation over the properties and return an Errors array of properties that have failed validation with a provided error message. It does not automagically link to the UI, but it keeps validation in the object itself rather than the UI.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜