INotifyDataErrorInfo與訪問數據庫(或通過服務邊界調用,這正是我假設您的意思)沒有任何關係。 INotifyDataErrorInfo是您查看模型可以實現的接口,以向您的視圖報告您的視圖模型具有驗證錯誤。掛鉤視圖模型的驗證以使用該界面仍然取決於您,除非這是WCF RIA Services爲您提供的免費功能,我並不贊同這一點。
我在我的視圖模型中使用[Required]屬性只是爲了給UI提示我的字段是必需的。我還在我的視圖模型中實現了INotifyDataErrorInfo,並確保在視圖模型中的任何屬性更改時調用我的驗證方法。當用戶執行保存命令時,我也手動調用我的驗證方法。
在我的情況下,我使用Fluent Validation庫來實現我的驗證邏輯。我還爲任何需要驗證邏輯的視圖模型構建了一個新的基類。
public class ValidatingViewModelBase<T> : ViewModelBase, IValidatingViewModel, INotifyDataErrorInfo
{
private readonly IValidator<T> _validator;
private readonly Dictionary<string, List<ValidationInfo>> _errors;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public ValidatingViewModelBase() : this(null, null)
{
}
public ValidatingViewModelBase(IValidator<T> validator) : this(validator, null)
{
}
public ValidatingViewModelBase(IValidator<T> validator, IMessenger messenger) : base(messenger)
{
_validator = validator;
_errors = new Dictionary<string, List<ValidationInfo>>();
}
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
return _errors.Values;
CreateValidationErrorInfoListForProperty(propertyName);
return _errors[propertyName];
}
public bool HasErrors
{
get { return _errors.Count > 0; }
}
protected virtual void AddValidationErrorForProperty(string propertyName, ValidationInfo validationInfo)
{
CreateValidationErrorInfoListForProperty(propertyName);
if (!_errors[propertyName].Contains(validationInfo))
{
_errors[propertyName].Add(validationInfo);
RaiseErrorsChanged(propertyName);
}
}
protected virtual void ClearValidationErrorsForProperty(string propertyName)
{
CreateValidationErrorInfoListForProperty(propertyName);
if (_errors[propertyName].Count > 0)
{
_errors[propertyName].Clear();
RaiseErrorsChanged(propertyName);
}
}
protected virtual void ClearAllValidationErrors()
{
foreach (var propertyName in _errors.Keys)
ClearValidationErrorsForProperty(propertyName);
_errors.Clear();
}
private void CreateValidationErrorInfoListForProperty(string propertyName)
{
if (!_errors.ContainsKey(propertyName))
_errors[propertyName] = new List<ValidationInfo>();
}
protected void RaiseErrorsChanged(string propertyName)
{
var handler = ErrorsChanged;
if (handler != null)
{
handler.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
}
}
protected override void RaisePropertyChanged(string propertyName)
{
Validate();
base.RaisePropertyChanged(propertyName);
}
public bool Validate()
{
if (_validator == null)
return true;
if (this is ILoadAndSaveData && !((ILoadAndSaveData)this).HasLoadedData)
return true;
ClearAllValidationErrors();
var results = _validator.Validate(this);
if (!results.IsValid)
{
foreach (var failure in results.Errors)
{
AddValidationErrorForProperty(failure.PropertyName,
new ValidationInfo(failure.ErrorMessage, ValidationType.Error));
}
}
return results.IsValid;
}
public void SendValidationMessage()
{
var message = _errors.Values.SelectMany(propertyValidations => propertyValidations)
.Aggregate("Please correct validation errors before saving.\r\n",
(current, validationInfo) => current + ("\r\n· " + validationInfo.Message));
MessengerInstance.Send(new ErrorMessage(new ErrorInfo { Message = message, Type = "Validation Error" }));
}
public bool ValidateAndSendValidationMessage()
{
var isValid = Validate();
if (!isValid)
{
SendValidationMessage();
}
return isValid;
}
}
public interface IValidatingViewModel
{
bool Validate();
void SendValidationMessage();
bool ValidateAndSendValidationMessage();
}
public enum ValidationType { Error, Warning }
public class ValidationInfo
{
public string Message { get; set; }
public ValidationType Type { get; set; }
public ValidationInfo(string message, ValidationType validationType)
{
Message = message;
Type = validationType;
}
public override string ToString()
{
var result = Message;
if (Type == ValidationType.Warning)
result = "Warning: " + result;
return result;
}
}
所以我的視圖模型繼承了這個新的基類。
public class ExampleViewModel : ValidatingViewModelBase<IExampleViewModel>, IExampleViewModel
{
public ExampleViewModel(IValidator<IExampleViewModel> validator,
IMessenger messenger)
: base(validator, messenger)
{
SaveCommand = new RelayCommand(SaveCommandExecute);
}
public RelayCommand SaveCommand { get; private set; }
private void SaveCommandExecute()
{
if (!ValidateAndSendValidationMessage())
return;
// save stuff here
}
}
我一定要爲每個視圖模型創建一個驗證器類。
public class ExampleValidator : AbstractValidator<IExampleViewModel>
{
public TripInformationValidator()
{
// validation logic here
}
}
希望這有助於!
是的!你是對的 - 但是文檔和示例利用這門課缺乏耐心,我很想知道更多,以及如何最好地將它與WCF集成RIA Services。我很驚訝WCF RIA在將變更集發送到服務器之前沒有對所有必填字段進行實體級檢查,擁有實體級的驗證方法將會非常棒,它可以強制執行所有屬性屬性在en tity。我有些驚訝MS會錯過這個驗證水平!我是否錯過了一些事情?從這裏開始:http://jeffhandley.com/archive/2009/10/16/validator.aspx – codeputer 2010-09-09 18:41:32