diff --git a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/AsyncRelayCommand.cs b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/AsyncRelayCommand.cs new file mode 100644 index 0000000..33b0592 --- /dev/null +++ b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/AsyncRelayCommand.cs @@ -0,0 +1,48 @@ +using System.Windows.Input; + +namespace JdeScoping.ConfigManager.ViewModels; + +/// +/// An async command implementation that properly handles async operations. +/// +public class AsyncRelayCommand : ICommand +{ + private readonly Func _execute; + private readonly Func? _canExecute; + private bool _isExecuting; + private EventHandler? _canExecuteChanged; + + public event EventHandler? CanExecuteChanged + { + add => _canExecuteChanged += value; + remove => _canExecuteChanged -= value; + } + + public AsyncRelayCommand(Func execute, Func? canExecute = null) + { + _execute = execute ?? throw new ArgumentNullException(nameof(execute)); + _canExecute = canExecute; + } + + public bool CanExecute(object? parameter) => !_isExecuting && (_canExecute?.Invoke() ?? true); + + public async void Execute(object? parameter) + { + if (!CanExecute(parameter)) return; + + _isExecuting = true; + RaiseCanExecuteChanged(); + + try + { + await _execute(); + } + finally + { + _isExecuting = false; + RaiseCanExecuteChanged(); + } + } + + public void RaiseCanExecuteChanged() => _canExecuteChanged?.Invoke(this, EventArgs.Empty); +} diff --git a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/RelayCommand.cs b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/RelayCommand.cs new file mode 100644 index 0000000..076536e --- /dev/null +++ b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/RelayCommand.cs @@ -0,0 +1,36 @@ +using System.Windows.Input; + +namespace JdeScoping.ConfigManager.ViewModels; + +/// +/// A command implementation that delegates to action methods. +/// +public class RelayCommand : ICommand +{ + private readonly Action _execute; + private readonly Predicate? _canExecute; + private EventHandler? _canExecuteChanged; + + public event EventHandler? CanExecuteChanged + { + add => _canExecuteChanged += value; + remove => _canExecuteChanged -= value; + } + + public RelayCommand(Action execute, Predicate? canExecute = null) + { + _execute = execute ?? throw new ArgumentNullException(nameof(execute)); + _canExecute = canExecute; + } + + public RelayCommand(Action execute, Func? canExecute = null) + : this(_ => execute(), canExecute != null ? _ => canExecute() : null) + { + } + + public bool CanExecute(object? parameter) => _canExecute?.Invoke(parameter) ?? true; + + public void Execute(object? parameter) => _execute(parameter); + + public void RaiseCanExecuteChanged() => _canExecuteChanged?.Invoke(this, EventArgs.Empty); +} diff --git a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/ViewModelBase.cs b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..752d7bf --- /dev/null +++ b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/ViewModelBase.cs @@ -0,0 +1,27 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace JdeScoping.ConfigManager.ViewModels; + +/// +/// Base class for all view models providing INotifyPropertyChanged implementation. +/// +public abstract class ViewModelBase : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected bool SetProperty(ref T field, T value, [CallerMemberName] string? propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) + return false; + + field = value; + OnPropertyChanged(propertyName); + return true; + } +}