2011-07-14 56 views
0

可能重複:
How can I handle a Validation.Error in my ViewModel instead of my View's code behind?WPF:如何實現大量的數據驗證在MVVM

如何在WPF使用數據驗證通常的例子通常只涉及定義錯誤控件的模板並在控件工具提示中顯示錯誤消息。我想要做的是創建一個所有ValidationErrors的集合,並將其顯示在ItemsControl中,並在用戶單擊ItemsControl中的關聯(錯誤)項目時關注無效控件。

在非MVVM項目不是太大的問題,因爲我可以調用上的每個控件Validation.GetErrors(OBJ),並建立我的收藏這一點。但是在MVVM中,ViewModel沒有直接鏈接到視圖,因此我無法調用ViewModel中的GetErrors()來構建我的集合,因爲我沒有任何對View上控件的引用。

有什麼訣竅綁定或路由從視圖到視圖模型的ValidationErrors或者這只是不可能在MVVM實現?

+2

爲此使用代碼隱藏並不違法。只需添加一點C#。 –

回答

1

數據驗證和mvvm的常用方法是使用IDataErrorInfo。你會在網上找到很多信息。

訣竅將焦點設置到你綁定到控件,是使用綁定屬性名。約什史密斯posted已經對此進行了博客。

0

下面是ViewModel基類的ValidationErrors屬性的代碼。我們的視圖模型基類實現INotifyPropertyChanged和IDataErrorInfo,並且對於Silverlight 4+還有INotifyDataErrorInfo。

請注意Silverlight和WPF的條件編譯語句。對於Silverlight,我們只需使用標準的INotifyDataErrorInfo機制通知視圖,對於WPF,我們觸發PropertyChanged事件來刷新受影響的控件。

這個用法很簡單。每個派生視圖模型類只需要設置ValidationErrors屬性,其他所有內容都由屬性設置器處理。 ValidationFailure失敗類屬於我們用來實現實際驗證邏輯的FluentValidation庫。

public IList<ValidationFailure> ValidationErrors 
{ 
    get { return GetPropertyValue(() => ValidationErrors); } 
    protected set 
    { 
    List<string> obsoleteValidationErrors = null; 

    // collect names of properties that do not longer have errors 
#if SILVERLIGHT 
    if (ErrorsChanged != null) 
#else 
    if (PropertyChanged != null) 
#endif 
    { 
     var oldErrorsCollection = ValidationErrors != null && ValidationErrors.Count > 0 ? ValidationErrors : new List<ValidationFailure>(); 
     var newErrorsCollection = value != null && value.Count > 0 ? value : new List<ValidationFailure>(); 
     var newPropertyNames = newErrorsCollection.Select(x => x.PropertyName).Distinct().ToDictionary(x => x); 

     // figure out which errors are no longer part of the new validation error collection 
     obsoleteValidationErrors = oldErrorsCollection.Where(x => 
     !newPropertyNames.ContainsKey(x.PropertyName)).Select(x => x.PropertyName).Distinct().ToList(); 
    } 

    if (SetPropertyValue(() => ValidationErrors, value)) 
    { 
     // fire event for properties that do not longer have errors 
     if (obsoleteValidationErrors != null) 
     { 
     foreach (var obsoleteValidationErrorPropertyName in obsoleteValidationErrors) 
#if SILVERLIGHT 
      ErrorsChanged(this, new DataErrorsChangedEventArgs(obsoleteValidationErrorPropertyName)); 
#else 
      OnPropertyChanged(obsoleteValidationErrorPropertyName); 
#endif 
     } 

     // fire event for properties that now have errors 
#if SILVERLIGHT 
     if (value != null && ErrorsChanged != null) 
#else 
     if (value != null && PropertyChanged != null) 
#endif 
     { 
     var propertyNames = value.Select(x => x.PropertyName).Distinct().ToList(); 

     foreach (var failedProperty in propertyNames) 
#if SILVERLIGHT 
      ErrorsChanged(this, new DataErrorsChangedEventArgs(failedProperty)); 
#else 
      OnPropertyChanged(failedProperty); 
#endif 
     } 
    } 
    } 
}