我目前有两个项目正在进行中。一个是WPF项目,并使用MvvmLight框架。另一个是使用FreshMVVM的Xamarin.Forms项目。这两个框架都有自己的INotifyPropertyChanged
实现,用作相应项目中所有ViewModel的基类。
在WPF项目中,我添加了一个实现INotifyDataErrorInfo的ValidatedViewModel,以便我可以轻松地对用户输入进行验证:
public abstract class ValidatedViewModel : ViewModelBase, INotifyDataErrorInfo
{
protected ValidatedViewModel() : base()
{
PropertyChanged += (sender, args) => ValidateProperty(args.PropertyName);
}
private readonly Dictionary<string, IEnumerable<string>> _validationErrors = new Dictionary<string, IEnumerable<string>>();
public IEnumerable GetErrors(string propertyName)
{
return _validationErrors.ContainsKey(propertyName) ? _validationErrors[propertyName] : null;
}
public bool HasErrors => _validationErrors.Any();
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
private void ValidateProperty(string propertyName)
{
var value = GetValue(propertyName);
var results = new List<ValidationResult>();
bool valid = Validator.TryValidateProperty(value,
new ValidationContext(this, null, null) {MemberName = propertyName}, results);
if (valid)
{
_validationErrors.Remove(propertyName);
}
else
{
_validationErrors[propertyName] = results.Select(r => r.ErrorMessage);
}
RaiseErrorsChanged(propertyName);
}
protected void RaiseErrorsChanged(string propertyName)
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
}
private object GetValue(string propertyName)
{
PropertyInfo propInfo = GetType().GetProperty(propertyName);
return propInfo.GetValue(this);
}
}
由于我也需要在我的Xamarin.Forms应用程序中进行验证,因此我必须复制并粘贴此类,仅更改基类。作为程序员,我讨厌不得不像这样重复代码块,所以我想将这个(以及一些其他常见功能,如http客户端包装器)放入一个可供两个项目使用的通用程序集中。不幸的是,我还没有找到实际共享ViewModelBase类的方法,因为尽管两个版本在其他方面完全相同,但它们都扩展了不同的基类。
如果我能做到这一点:
public abstract class ValidatedViewModel<BaseViewModel> : BaseViewModel, INotifyDataErrorInfo where BaseViewModel : INotifyPropertyChanged
或者这个:
public class WPFViewModelBase : ViewModelBase, ValidatedeViewModel
public class XFViewModelBase : FreshBasePageModel, ValidatedViewModel
那么这不会成为问题。不幸的是,据我所知,这两件事都是不可能的。
跳出来的唯一解决方案是拥有一个ViewModelValidator
类WPFViewModelBase
和XFViewModelBase
每个实例化构建,并转发INofityDataErrorInfo
调用,但这看起来很笨重,并没有完全消除代码重复,因为我仍然会在两个不同的地方拥有所有相同的转发代码。
有什么方法可以消除所有代码重复吗?