diff --git a/Toolkit.Foundation/IValidation.cs b/Toolkit.Foundation/IValidation.cs index a4d318c..3cbacf7 100644 --- a/Toolkit.Foundation/IValidation.cs +++ b/Toolkit.Foundation/IValidation.cs @@ -14,7 +14,10 @@ public interface IValidation : ValidationRule[] rules, ValidationTrigger trigger = ValidationTrigger.Deferred); - bool Validate(); + Task Validate(Expression> property, + ValidationRule[] rules); - bool Validate(string name); + Task Validate(); + + Task Validate(string name); } \ No newline at end of file diff --git a/Toolkit.Foundation/Validation.cs b/Toolkit.Foundation/Validation.cs index b76561f..035485c 100644 --- a/Toolkit.Foundation/Validation.cs +++ b/Toolkit.Foundation/Validation.cs @@ -27,7 +27,7 @@ public class Validation(IValidatorCollection validators) : if (trigger is ValidationTrigger.Immediate) { - Validate(name); + _ = Validate(name); } } @@ -37,7 +37,28 @@ public class Validation(IValidatorCollection validators) : PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } - public bool Validate(string name) + + public async Task Validate(Expression> property, + ValidationRule[] rules) + { + string? name = GetPropertyName(property); + Validator validator = new(name, rules); + + (bool isValid, string? message) = await validator.TryValidate(); + + if (!isValid) + { + errors[name] = message ?? ""; + } + + OnPropertyChanged(nameof(Errors), null, null); + OnPropertyChanged(nameof(HasErrors), null, null); + + return !HasErrors; + } + + + public async Task Validate(string name) { if (Errors.ContainsKey(name)) { @@ -48,7 +69,8 @@ public class Validation(IValidatorCollection validators) : { if (validator is not null) { - if (!validator.TryValidate(out string? message)) + (bool isValid, string? message) = await validator.TryValidate(); + if (!isValid) { errors[name] = message ?? ""; } @@ -61,14 +83,15 @@ public class Validation(IValidatorCollection validators) : return !HasErrors; } - public bool Validate() + public async Task Validate() { errors.Clear(); foreach (Validator? validator in Validators) { if (validator.PropertyName is string name) { - if (!validator.TryValidate(out string? message)) + (bool isValid, string? message) = await validator.TryValidate(); + if (!isValid) { errors[name] = message ?? ""; } diff --git a/Toolkit.Foundation/ValidationRule.cs b/Toolkit.Foundation/ValidationRule.cs index d420905..c024ac4 100644 --- a/Toolkit.Foundation/ValidationRule.cs +++ b/Toolkit.Foundation/ValidationRule.cs @@ -2,26 +2,49 @@ public class ValidationRule { - public ValidationRule(Func validation, + private readonly Func? syncValidation; + private readonly Func>? asyncValidation; + + public ValidationRule(Func validation, string message) { - Validation = validation; - Message = new Func(() => message); + syncValidation = validation; + Message = message; + } + + public ValidationRule(Func> validation, + string message) + { + asyncValidation = validation; + Message = message; } public ValidationRule(Func validation) { - Validation = validation; + syncValidation = validation; + Message = ""; } - public ValidationRule(Func validation, - Func message) + public ValidationRule(Func> validation) { - Validation = validation; - Message = message; + asyncValidation = validation; + Message = ""; } - public Func? Message { get; } + public async Task ValidateAsync() + { + if (syncValidation is not null) + { + return syncValidation(); + } - public Func? Validation { get; } + if (asyncValidation is not null) + { + return await asyncValidation(); + } + + return false; + } + + public string Message { get; } } diff --git a/Toolkit.Foundation/Validator.cs b/Toolkit.Foundation/Validator.cs index e1e59f1..c53d751 100644 --- a/Toolkit.Foundation/Validator.cs +++ b/Toolkit.Foundation/Validator.cs @@ -1,33 +1,22 @@ -using System.Diagnostics.CodeAnalysis; +namespace Toolkit.Foundation; -namespace Toolkit.Foundation; - -public class Validator +public class Validator(string propertyName, + ValidationRule[] rules) { - private readonly ValidationRule[] rules = []; + private readonly ValidationRule[] rules = rules; - public Validator(string propertyName, - ValidationRule[] rules) + public string? PropertyName { get; } = propertyName; + + public async Task<(bool isValid, string? message)> TryValidate() { - PropertyName = propertyName; - this.rules = rules; - } - - public string? PropertyName { get; } - - public bool TryValidate([MaybeNull] out string message) - { - message = ""; - foreach (ValidationRule rule in rules) { - if (rule.Validation?.Invoke() == false) + if (!await rule.ValidateAsync()) { - message = rule.Message?.Invoke(); - return false; + return (false, rule.Message); } } - return true; + return (true, null); } } diff --git a/Toolkit.UI.Avalonia/KeyBindingTriggerBehaviour.cs b/Toolkit.UI.Avalonia/KeyBindingTriggerBehaviour.cs index 8946c24..6d506f6 100644 --- a/Toolkit.UI.Avalonia/KeyBindingTriggerBehaviour.cs +++ b/Toolkit.UI.Avalonia/KeyBindingTriggerBehaviour.cs @@ -12,12 +12,21 @@ public class KeyBindingTriggerBehaviour : public static readonly StyledProperty GestureProperty = AvaloniaProperty.Register(nameof(Gesture)); + public static readonly StyledProperty IsEnabledProperty = + AvaloniaProperty.Register(nameof(IsEnabled), true); + public KeyGesture Gesture { get => GetValue(GestureProperty); set => SetValue(GestureProperty, value); } + public bool IsEnabled + { + get => GetValue(IsEnabledProperty); + set => SetValue(IsEnabledProperty, value); + } + public event EventHandler? CanExecuteChanged; protected override void OnAttached() @@ -38,6 +47,11 @@ public class KeyBindingTriggerBehaviour : public bool CanExecute(object? parameter) => true; - public void Execute(object? parameter) => - Interaction.ExecuteActions(AssociatedObject, Actions, null); + public void Execute(object? parameter) + { + if (IsEnabled) + { + Interaction.ExecuteActions(AssociatedObject, Actions, null); + } + } } \ No newline at end of file