Added Validation logics

This commit is contained in:
TheXamlGuy
2024-06-16 13:42:36 +01:00
parent bca4a32964
commit a0b074c9e0
12 changed files with 160 additions and 58 deletions
-2
View File
@@ -94,8 +94,6 @@ public class ContentDialogHandler(IDispatcher dispatcher) :
deactivatable.DeactivateHandler += DeactivateHandler;
}
// A hack to wait for the dialog to finish loading up to make it appear more responsive
await Task.Delay(250);
if (content is IActivated activated)
{
await activated.OnActivated();
+3
View File
@@ -36,6 +36,9 @@ public class ComponentBuilder :
services.AddTransient<IPublisher, Publisher>();
services.AddTransient<IMediator, Mediator>();
services.AddTransient<IValidation, Validation>();
services.AddTransient<IValidatorCollection, ValidatorCollection>();
services.AddTransient<IContentFactory, ContentFactory>();
services.AddTransient<INavigation, Navigation>();
+4 -4
View File
@@ -29,13 +29,13 @@ public class DefaultHostBuilder :
services.AddScoped<SubscriptionCollection>();
services.AddTransient<IHandlerProvider, HandlerProvider>();
services.AddTransient<ISubscriber, Subscriber>();
services.AddTransient<ISubscriber, Subscriber>();
services.AddScoped<ISubscriber, Subscriber>();
services.AddTransient<IPublisher, Publisher>();
services.AddTransient<IMediator, Mediator>();
services.AddTransient<IValidation, Validation>();
services.AddTransient<IValidatorCollection, ValidatorCollection>();
services.AddScoped<IProxyService<IPublisher>>(provider =>
new ProxyService<IPublisher>(provider.GetRequiredService<IPublisher>()));
+20
View File
@@ -0,0 +1,20 @@
using System.ComponentModel;
using System.Linq.Expressions;
namespace Toolkit.Foundation;
public interface IValidation :
INotifyPropertyChanged
{
ValidationErrorCollection Errors { get; }
bool HasErrors { get; }
void Add<TProperty>(Expression<Func<TProperty>> property,
ValidationRule[] rules,
ValidationTrigger trigger = ValidationTrigger.Deferred);
bool Validate();
bool Validate(string name);
}
+10
View File
@@ -0,0 +1,10 @@
namespace Toolkit.Foundation;
public record Validate
{
public static ValidateEventArgs<TValue> As<TValue>(TValue value) =>
new(value);
public static ValidateEventArgs<TValue> As<TValue>() where TValue : new() =>
new(new TValue());
}
+3
View File
@@ -0,0 +1,3 @@
namespace Toolkit.Foundation;
public record ValidateEventArgs<TValue>(TValue Value);
+86 -7
View File
@@ -1,10 +1,89 @@
namespace Toolkit.Foundation;
using System.ComponentModel;
using System.Linq.Expressions;
public record Validation
namespace Toolkit.Foundation;
public class Validation(IValidatorCollection validators) :
IValidation
{
public static ValidationEventArgs<TValue> As<TValue>(TValue value) =>
new(value);
public event PropertyChangedEventHandler? PropertyChanged;
public static ValidationEventArgs<TValue> As<TValue>() where TValue : new() =>
new(new TValue());
}
public ValidationErrorCollection Errors { get; } = [];
public bool HasErrors =>
Errors.Count > 0;
internal IValidatorCollection Validators { get; } = validators;
public void Add<TProperty>(Expression<Func<TProperty>> property,
ValidationRule[] rules,
ValidationTrigger trigger = ValidationTrigger.Deferred)
{
string? name = GetPropertyName(property);
Validators.Add(name, new Validator(name, rules));
if (trigger is ValidationTrigger.Immediate)
{
Validate(name);
}
}
public virtual void OnPropertyChanged(string propertyName,
object? before, object? after)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public bool Validate(string name)
{
if (Errors.ContainsKey(name))
{
Errors.Remove(name);
}
if (Validators.TryGet(name, out Validator? validator))
{
if (validator is not null)
{
if (!validator.TryValidate(out string? message))
{
Errors[name] = message ?? "";
}
}
}
OnPropertyChanged(nameof(Errors), null, null);
OnPropertyChanged(nameof(HasErrors), null, null);
return !HasErrors;
}
public bool Validate()
{
Errors.Clear();
foreach (Validator? validator in Validators)
{
if (validator.PropertyName is string name)
{
if (!validator.TryValidate(out string? message))
{
Errors[name] = message ?? "";
}
}
}
OnPropertyChanged(nameof(Errors), null, null);
OnPropertyChanged(nameof(HasErrors), null, null);
return !HasErrors;
}
private string GetPropertyName<T>(Expression<Func<T>> predicate)
{
Expression? body = predicate.Body;
MemberExpression? memberExpression = body as MemberExpression ??
(MemberExpression)((UnaryExpression)body).Operand;
return memberExpression.Member.Name;
}
}
@@ -5,10 +5,11 @@ using System.Diagnostics.CodeAnalysis;
namespace Toolkit.Foundation;
public class ValidationErrorCollection : IDictionary<string, string>,
IDictionary,
INotifyCollectionChanged,
INotifyPropertyChanged
public class ValidationErrorCollection :
IDictionary<string, string>,
IDictionary,
INotifyCollectionChanged,
INotifyPropertyChanged
{
private Dictionary<string, string> items;
@@ -41,11 +42,7 @@ public class ValidationErrorCollection : IDictionary<string, string>,
public string this[string key]
{
get
{
return items[key];
}
get => items.ContainsKey(key) ? items[key] : "";
set
{
bool replace = items.TryGetValue(key, out var old);
@@ -54,7 +51,8 @@ public class ValidationErrorCollection : IDictionary<string, string>,
if (replace)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]"));
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, new KeyValuePair<string, string>(key, value), new KeyValuePair<string, string>(key, old!)));
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace,
new KeyValuePair<string, string>(key, value), new KeyValuePair<string, string>(key, old!)));
}
else
{
@@ -1,3 +0,0 @@
namespace Toolkit.Foundation;
public record ValidationEventArgs<TValue>(TValue Value);
@@ -1,22 +1,27 @@
namespace Toolkit.Foundation;
public class PropertyValidator
public class ValidationRule
{
public PropertyValidator(Func<bool> validation,
public ValidationRule(Func<bool> validation,
string message)
{
Validation = validation;
Message = new Func<string>(() => message);
}
public PropertyValidator(Func<bool> validation,
public ValidationRule(Func<bool> validation)
{
Validation = validation;
}
public ValidationRule(Func<bool> validation,
Func<string> message)
{
Validation = validation;
Message = message;
}
public Func<string> Message { get; }
public Func<string>? Message { get; }
public Func<bool>? Validation { get; }
}
+7
View File
@@ -0,0 +1,7 @@
namespace Toolkit.Foundation;
public enum ValidationTrigger
{
Deferred,
Immediate
}
+10 -28
View File
@@ -4,48 +4,30 @@ namespace Toolkit.Foundation;
public class Validator
{
private readonly Action? propertyChanged;
private readonly PropertyValidator? propertyValidation;
private readonly ValidationRule[] rules = [];
internal Validator(string propertyName,
Action propertyChanged)
public Validator(string propertyName,
ValidationRule[] rules)
{
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;
this.rules = rules;
}
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)
foreach (ValidationRule rule in rules)
{
message = propertyValidation.Message.Invoke();
return false;
if (rule.Validation?.Invoke() == false)
{
message = rule.Message?.Invoke();
return false;
}
}
propertyChanged?.Invoke();
return true;
}
}