2010-07-27 46 views
0

所以我有一個DataGridView用於顯示自定義模型列表。 這裏是一個模型的一些示例代碼:Databoud DataGridView每列驗證

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; 
    } 
} 

現在讓我們說我是綁定這些模型的列表(或IEnumerable的),像這樣

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

(我們可以認爲這個列表回報有效的,否則它不會被存儲)。

現在上的DataGridView中RowValidating事件,我可以通過訪問IsValid屬性驗證整個行並設置Rows[].ErrorText,像這樣:

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; 
    } 
} 

現在,我真正想做的事情(不復制並粘貼遍佈整個地方的代碼),驗證每個屬性並設置Rows[].Cells[].ErrorText屬性(這將顯示每個單元而不是整行的錯誤)。

我應該怎麼辦?

也許用自定義屬性的東西,然後反射獲取屬性名稱和訪問單元格的方式?

希望這一切都有道理!

回答

1

解決了!

有一個抽象的屬性,像這樣:

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

和像這樣實現:

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 
} 

然後修改Value2屬性,像這樣:

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

,並在任一RowValidatingCellValidating活動做某事l ike 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; 
} 

和bam每個屬性的錯誤,用數據綁定!

+0

+1你應該看看企業庫 - 驗證塊做類似這個... – 2010-07-27 21:20:08

+0

臭味的是,這是一個一次性的應用程序,將在未來6個月內被取代!但我會看看,歡呼:) – PostMan 2010-07-27 21:24:20

0

您能否使用CellValidating事件?此事件與RowValidating類似,除非在您退出單元格時發生。

另外,如果你的行代表一個業務對象,那麼你就可以暴露出Validate方法,將在性能執行驗證並返回一個Errors陣列已驗證失敗與提供的錯誤信息屬性。它不會自動鏈接到UI,但它會在對象本身而不是用戶界面中進行驗證。