From bca4a32964c153330d07e6512bd397912332a03a Mon Sep 17 00:00:00 2001 From: TheXamlGuy Date: Sat, 15 Jun 2024 22:16:03 +0100 Subject: [PATCH] Validation work --- Toolkit.Foundation/IValidatorCollection.cs | 11 ++ Toolkit.Foundation/PropertyValidator.cs | 22 +++ .../ValidationErrorCollection.cs | 154 ++++++++++++++++++ Toolkit.Foundation/Validator.cs | 51 ++++++ Toolkit.Foundation/ValidatorCollection.cs | 24 +++ 5 files changed, 262 insertions(+) create mode 100644 Toolkit.Foundation/IValidatorCollection.cs create mode 100644 Toolkit.Foundation/PropertyValidator.cs create mode 100644 Toolkit.Foundation/ValidationErrorCollection.cs create mode 100644 Toolkit.Foundation/Validator.cs create mode 100644 Toolkit.Foundation/ValidatorCollection.cs diff --git a/Toolkit.Foundation/IValidatorCollection.cs b/Toolkit.Foundation/IValidatorCollection.cs new file mode 100644 index 0000000..324524c --- /dev/null +++ b/Toolkit.Foundation/IValidatorCollection.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Toolkit.Foundation; + +public interface IValidatorCollection : + IReadOnlyCollection +{ + void Add(string key, Validator binder); + + bool TryGet(string key, [MaybeNull] out Validator? value); +} diff --git a/Toolkit.Foundation/PropertyValidator.cs b/Toolkit.Foundation/PropertyValidator.cs new file mode 100644 index 0000000..fac8d17 --- /dev/null +++ b/Toolkit.Foundation/PropertyValidator.cs @@ -0,0 +1,22 @@ +namespace Toolkit.Foundation; + +public class PropertyValidator +{ + public PropertyValidator(Func validation, + string message) + { + Validation = validation; + Message = new Func(() => message); + } + + public PropertyValidator(Func validation, + Func message) + { + Validation = validation; + Message = message; + } + + public Func Message { get; } + + public Func? Validation { get; } +} diff --git a/Toolkit.Foundation/ValidationErrorCollection.cs b/Toolkit.Foundation/ValidationErrorCollection.cs new file mode 100644 index 0000000..31f4d7b --- /dev/null +++ b/Toolkit.Foundation/ValidationErrorCollection.cs @@ -0,0 +1,154 @@ +using System.Collections.Specialized; +using System.Collections; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; + +namespace Toolkit.Foundation; + +public class ValidationErrorCollection : IDictionary, + IDictionary, + INotifyCollectionChanged, + INotifyPropertyChanged +{ + private Dictionary items; + + public ValidationErrorCollection() + { + items = []; + } + + public event NotifyCollectionChangedEventHandler? CollectionChanged; + + public event PropertyChangedEventHandler? PropertyChanged; + + public int Count => items.Count; + + bool IDictionary.IsFixedSize => ((IDictionary)items).IsFixedSize; + + public bool IsReadOnly => false; + + bool ICollection.IsSynchronized => ((IDictionary)items).IsSynchronized; + + public ICollection Keys => items.Keys; + + ICollection IDictionary.Keys => ((IDictionary)items).Keys; + + object ICollection.SyncRoot => ((IDictionary)items).SyncRoot; + + public ICollection Values => items.Values; + + ICollection IDictionary.Values => ((IDictionary)items).Values; + + public string this[string key] + { + get + { + return items[key]; + } + + set + { + bool replace = items.TryGetValue(key, out var old); + items[key] = value; + + if (replace) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]")); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, new KeyValuePair(key, value), new KeyValuePair(key, old!))); + } + else + { + NotifyAdd(key, value); + } + } + } + + object? IDictionary.this[object key] + { + get => ((IDictionary)items)[key]; + set => ((IDictionary)items)[key] = value; + } + + public void Add(string key, string value) + { + items.Add(key, value); + NotifyAdd(key, value); + } + + void ICollection>.Add(KeyValuePair item) => + Add(item.Key, item.Value); + + void IDictionary.Add(object key, object? value) => + Add((string)key, (string)value!); + + public void Clear() + { + Dictionary old = items; + items = []; + + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item")); + + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, old.ToArray(), -1)); + } + + bool ICollection>.Contains(KeyValuePair item) => + items.Contains(item); + + bool IDictionary.Contains(object key) => + ((IDictionary)items).Contains(key); + + public bool ContainsKey(string key) => items.ContainsKey(key); + + public void CopyTo(KeyValuePair[] array, int arrayIndex) => + ((IDictionary)items).CopyTo(array, arrayIndex); + + void ICollection.CopyTo(Array array, int index) => + ((ICollection)items).CopyTo(array, index); + + public IEnumerator> GetEnumerator() => + items.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => + items.GetEnumerator(); + + IDictionaryEnumerator IDictionary.GetEnumerator() => + ((IDictionary)items).GetEnumerator(); + + public bool Remove(string key) + { + if (items.TryGetValue(key, out var value)) + { + items.Remove(key); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]")); + + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new[] { new KeyValuePair(key, value) }, -1)); + + return true; + } + else + { + return false; + } + } + + public bool Contains(string key) => + items.ContainsKey(key); + + bool ICollection>.Remove(KeyValuePair item) => + Remove(item.Key); + + void IDictionary.Remove(object key) => Remove((string)key); + + public bool TryGetValue(string key, [MaybeNullWhen(false)] out string value) => items.TryGetValue(key, out value); + + private void NotifyAdd(string key, string value) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]")); + + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, + new[] { new KeyValuePair(key, value) }, -1)); + } +} diff --git a/Toolkit.Foundation/Validator.cs b/Toolkit.Foundation/Validator.cs new file mode 100644 index 0000000..5e8257a --- /dev/null +++ b/Toolkit.Foundation/Validator.cs @@ -0,0 +1,51 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Toolkit.Foundation; + +public class Validator +{ + private readonly Action? propertyChanged; + private readonly PropertyValidator? propertyValidation; + + internal Validator(string propertyName, + Action propertyChanged) + { + PropertyName = propertyName; + this.propertyChanged = propertyChanged; + } + + internal Validator(string propertyName, + Action propertyChanged, + PropertyValidator validation) + { + PropertyName = propertyName; + + this.propertyChanged = propertyChanged; + propertyValidation = validation; + } + + internal Validator(string propertyName, + PropertyValidator validation) + { + PropertyName = propertyName; + propertyValidation = validation; + } + + public string? PropertyName { get; } + + public void Set() => propertyChanged?.Invoke(); + + public bool TryValidate([MaybeNull] out string message) + { + message = ""; + + if (propertyValidation is not null && propertyValidation.Validation?.Invoke() == false) + { + message = propertyValidation.Message.Invoke(); + return false; + } + + propertyChanged?.Invoke(); + return true; + } +} diff --git a/Toolkit.Foundation/ValidatorCollection.cs b/Toolkit.Foundation/ValidatorCollection.cs new file mode 100644 index 0000000..b58081a --- /dev/null +++ b/Toolkit.Foundation/ValidatorCollection.cs @@ -0,0 +1,24 @@ +using System.Diagnostics.CodeAnalysis; +using System.Collections; + +namespace Toolkit.Foundation; + +public class ValidatorCollection : + IValidatorCollection +{ + private readonly Dictionary binders = []; + + public int Count => binders.Count; + + public void Add(string key, Validator binder) => + binders.Add(key, binder); + + public IEnumerator GetEnumerator() => + binders.Select(x => x.Value).GetEnumerator(); + + public bool TryGet(string key, [MaybeNull] out Validator? value) => + binders.TryGetValue(key, out value); + + IEnumerator IEnumerable.GetEnumerator() => + binders.Select(x => x.Value).GetEnumerator(); +}