Created
October 11, 2012 16:36
-
-
Save nseba/3873680 to your computer and use it in GitHub Desktop.
ViewModel with validation support using INotifyDataErrorInfo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.ComponentModel.DataAnnotations; | |
using System.Linq; | |
using System.Runtime.CompilerServices; | |
class ViewModel : INotifyDataErrorInfo, INotifyPropertyChanged | |
{ | |
#region NotifyPropertyChanged related members | |
public event PropertyChangedEventHandler PropertyChanged; | |
public bool SetProperty<T>(ref T backingStorage, T value, [CallerMemberName] string propertyName = null) | |
{ | |
if (Equals(backingStorage, value)) return false; | |
backingStorage = value; | |
RaisePropertyChanged(propertyName); | |
return true; | |
} | |
public bool SetProperty<T>(Func<T> getter, Action<T> setter, T value, string propertyName) | |
{ | |
T backingStorage = getter(); | |
if (!SetProperty(ref backingStorage, value, propertyName)) | |
{ | |
return false; | |
} | |
setter(backingStorage); | |
return true; | |
} | |
public void RaisePropertyChanged([CallerMemberName]string propertyName = null) | |
{ | |
var handler = PropertyChanged; | |
if (handler != null) | |
{ | |
handler(this, new PropertyChangedEventArgs(propertyName)); | |
} | |
} | |
#endregion | |
protected bool SetPropertyAndValidate<T>(Func<T> getter, Action<T> setter, T value, [CallerMemberName] string propertyName = null) | |
{ | |
ICollection<ValidationResult> validationResults = new List<ValidationResult>(); | |
ValidationContext validationContext = CreateValidationContext<T>(propertyName); | |
if (!Validator.TryValidateProperty(value, validationContext, validationResults)) | |
{ | |
SetErrors(propertyName, validationResults); | |
return false; | |
} | |
ClearErrors(propertyName); | |
return SetProperty(getter, setter, value, propertyName); | |
} | |
#region NotifyDataErrorInfo related members | |
private readonly IDictionary<string, IList<string>> errors = new Dictionary<string, IList<string>>(); | |
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; | |
public IEnumerable GetErrors(string propertyName) | |
{ | |
IList<string> list; | |
return errors.TryGetValue(propertyName, out list) ? list : Enumerable.Empty<string>(); | |
} | |
public bool HasErrors | |
{ | |
get | |
{ | |
return errors.Count > 0; | |
} | |
} | |
private ValidationContext CreateValidationContext<T>(string propertyName) | |
{ | |
var validationContext = new ValidationContext(this) | |
{ | |
MemberName = propertyName | |
}; | |
return validationContext; | |
} | |
private void ClearErrors(string propertyName) | |
{ | |
errors.Remove(propertyName); | |
RaiseErrorsChanged(propertyName); | |
} | |
private void SetErrors(string propertyName, IEnumerable<ValidationResult> validationResults) | |
{ | |
List<string> propertyErrors = validationResults | |
.Select(x => x.ErrorMessage) | |
.ToList(); | |
errors[propertyName] = propertyErrors; | |
RaiseErrorsChanged(propertyName); | |
} | |
private void RaiseErrorsChanged(string propertyName) | |
{ | |
EventHandler<DataErrorsChangedEventArgs> handler = ErrorsChanged; | |
if (handler != null) | |
{ | |
handler(this, new DataErrorsChangedEventArgs(propertyName)); | |
} | |
RaisePropertyChanged("HasErrors"); | |
} | |
protected void ValidateObject() | |
{ | |
ICollection<ValidationResult> validationResults = new List<ValidationResult>(); | |
bool isValid = Validator.TryValidateObject(this, new ValidationContext(this), validationResults); | |
if (isValid) | |
{ | |
ClearErrors(string.Empty); | |
return; | |
} | |
IEnumerable<IGrouping<string, ValidationResult>> allResults = validationResults | |
.SelectMany(result => result.MemberNames.Select(member => new KeyValuePair<string, ValidationResult>(member, result))) | |
.GroupBy(x => x.Key, pair => pair.Value); | |
foreach (var memberResults in allResults) | |
{ | |
SetErrors(memberResults.Key, memberResults); | |
} | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment