MVVM/新实体/必需属性/提交前验证
我正在通过WCF RIA Services元数据类在上使用Required属性,该类下面是实体框架 我创建了一个新实体,并让视图绑定到视图模型。用户查看它一段时间,单击周围,然后尝试保存它 这里的场景是,用户没有在具有必填字段属性的字段中单击或制表符 在提交数据之前,我如何确保所有必填字段都有数据 Winforms也有同样的问题,我使用它循环表单中的所有字段,以确保所有验证程序都已通过 我必须重新编写页面的基类吗 是否有办法确保在将属性验证发送回服务器之前触发所有属性验证?我是否必须使用反射并拾取具有必需属性的所有字段 我使用的是实体框架,我研究过INotifyDataErrorInfo——但这是在访问数据库之后使用的(据我所知) 我知道我不是第一个遇到这种情况的人,但在我的研究中,我找不到这种情况的好例子。与数据库的访问(或通过服务边界的呼叫,我认为这是你的意思)没有任何关系。INotifyDataErrorInfo是视图模型可以实现的接口,用于向视图报告视图模型存在验证错误。连接视图模型的验证以使用该接口仍然取决于您,除非WCF RIA Services免费为您提供了这一点,我对此并不乐观 我在视图模型中使用[Required]属性只是为了向UI提示我的字段是必需的。我还在视图模型中实现INotifyDataErrorInfo,并确保在视图模型中的任何属性发生更改时调用我的验证方法。当用户执行save命令时,我还手动调用我的验证方法 在我的例子中,我使用库来实现我的验证逻辑。我还为任何需要验证逻辑的视图模型构建了一个新的基类MVVM/新实体/必需属性/提交前验证,mvvm,mvvm-light,wcf-ria-services,Mvvm,Mvvm Light,Wcf Ria Services,我正在通过WCF RIA Services元数据类在上使用Required属性,该类下面是实体框架 我创建了一个新实体,并让视图绑定到视图模型。用户查看它一段时间,单击周围,然后尝试保存它 这里的场景是,用户没有在具有必填字段属性的字段中单击或制表符 在提交数据之前,我如何确保所有必填字段都有数据 Winforms也有同样的问题,我使用它循环表单中的所有字段,以确保所有验证程序都已通过 我必须重新编写页面的基类吗 是否有办法确保在将属性验证发送回服务器之前触发所有属性验证?我是否必须使用反射并拾
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;
}
}
公共类验证ViewModelBase:ViewModelBase、IValidingViewModel、INotifyDataErrorInfo
{
专用只读IValidator_验证程序;
私有只读字典_错误;
公共事件事件处理程序错误更改;
public ValidatingViewModelBase():这(null,null)
{
}
公共验证ViewModelBase(IValidator验证程序):此(验证程序,null)
{
}
公共验证ViewModelBase(IValidator验证程序、IMessenger messenger):基本(messenger)
{
_验证器=验证器;
_错误=新字典();
}
公共IEnumerable GetErrors(字符串propertyName)
{
if(string.IsNullOrEmpty(propertyName))
返回_errors.Values;
CreateValidationErrorFolistForProperty(propertyName);
返回_错误[propertyName];
}
公共布尔错误
{
获取{return\u errors.Count>0;}
}
受保护的虚拟void AddValidationErrorForProperty(字符串propertyName,ValidationInfo ValidationInfo)
{
CreateValidationErrorFolistForProperty(propertyName);
如果(!\u错误[propertyName]。包含(validationInfo))
{
_错误[propertyName]。添加(validationInfo);
RaiserRorschanged(propertyName);
}
}
受保护的虚拟void ClearValidationErrorForProperty(字符串propertyName)
{
CreateValidationErrorFolistForProperty(propertyName);
如果(\u错误[propertyName].Count>0)
{
_错误[propertyName]。清除();
RaiserRorschanged(propertyName);
}
}
受保护的虚拟空间ClearAllValidationErrors()
{
foreach(在_errors.Keys中的var propertyName)
ClearValidationErrorForProperty(propertyName);
_错误。清除();
}
私有void CreateValidationErrorFolistForProperty(字符串propertyName)
{
如果(!\u errors.ContainsKey(propertyName))
_错误[propertyName]=新列表();
}
受保护的无效RAISEERROSCHANGED(字符串属性名称)
{
var handler=ErrorsChanged;
if(处理程序!=null)
{
Invoke(这是新的DataErrorsChangedEventArgs(propertyName));
}
}
受保护的覆盖无效RaisePropertyChanged(字符串propertyName)
{
验证();
base.RaisePropertyChanged(propertyName);
}
公共bool验证()
{
if(_validator==null)
返回true;
if(这是ILoadAndSaveData&&!((ILoadAndSaveData)this).hasloaddeddata)
返回true;
ClearAllValidationErrors();
var results=\u validator.Validate(此);
如果(!results.IsValid)
{
foreach(结果中的var失败。错误)
{
AddValidationErrorForProperty(failure.PropertyName,
新的ValidationInfo(failure.ErrorMessage,ValidationType.Error));
}
}
返回results.IsValid;
}
public void SendValidationMessage()
{
var message=\u errors.Values.SelectMany(propertyValidations=>propertyValidations)
.Aggregate(“保存前请更正验证错误。\r\n”,
(当前,validationInfo)=>current+(“\r\n·”+validationInfo.Message));
Send(newerrormessage(newerrorinfo{Message=Message,Type=“Validation Error”}));
}
public bool ValidateAndSendValidationMessage()
{
var isValid=Validate();
如果(!isValid)
{
SendValidationMessage();
}
返回有效;
}
}
公共界面IValidingViewModel
{
bool验证();
void SendValidationMessage();
bool ValidateAndSendValidationMessage();
}
公共枚举验证类型{错误,警告}
公共类验证信息
{
公共字符串消息{get;set;}
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
}
}