using System; using System.Diagnostics.CodeAnalysis; using CommunityToolkit.Mvvm.Input; using NLog; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Core.Extensions; namespace StabilityMatrix.Avalonia.Extensions; [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public static class RelayCommandExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); /// /// Attach an error handler to the command that will invoke the given action when an exception occurs. /// /// The command to attach the error handler to. /// The action to invoke when an exception occurs. /// Thrown if the command was not created with the FlowExceptionsToTaskScheduler option enabled. public static T WithErrorHandler(this T command, Action onError) where T : IAsyncRelayCommand { if (command is AsyncRelayCommand relayCommand) { // Check that the FlowExceptionsToTaskScheduler flag is set var options = relayCommand.GetPrivateField("options"); if (!options.HasFlag(AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler)) { throw new ArgumentException( "The command must be created with the FlowExceptionsToTaskScheduler option enabled" ); } } command.PropertyChanged += (sender, e) => { if (sender is not IAsyncRelayCommand senderCommand) { return; } // On ExecutionTask updates, check if there is an exception if ( e.PropertyName == nameof(AsyncRelayCommand.ExecutionTask) && senderCommand.ExecutionTask is { Exception: { } exception } ) { onError(exception); } }; return command; } /// /// Attach an error handler to the command that will log the error and show a notification. /// /// The command to attach the error handler to. /// The notification service to use to show the notification. /// The log level to use when logging the error. Defaults to LogLevel.Error /// Thrown if the command was not created with the FlowExceptionsToTaskScheduler option enabled. public static T WithNotificationErrorHandler( this T command, INotificationService notificationService, LogLevel? logLevel = default ) where T : IAsyncRelayCommand { logLevel ??= LogLevel.Error; return command.WithErrorHandler(e => { Logger.Log(logLevel, e, "Error executing command"); notificationService.ShowPersistent("Error", $"[{e.GetType().Name}] {e.Message}"); }); } }