Skip to content

Commit

Permalink
Merge pull request #2887 from PrismLibrary/dev/ds/command-catch
Browse files Browse the repository at this point in the history
Adding Exception Handler
  • Loading branch information
dansiegel authored Jul 9, 2023
2 parents d8d47b8 + ee47bff commit a128f20
Show file tree
Hide file tree
Showing 6 changed files with 696 additions and 8 deletions.
123 changes: 121 additions & 2 deletions src/Prism.Core/Commands/DelegateCommand.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Windows.Input;
using Prism.Properties;

Expand Down Expand Up @@ -46,7 +47,17 @@ public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
///</summary>
public void Execute()
{
_executeMethod();
try
{
_executeMethod();
}
catch (Exception ex)
{
if (!ExceptionHandler.CanHandle(ex))
throw;

ExceptionHandler.Handle(ex, null);
}
}

/// <summary>
Expand All @@ -55,7 +66,19 @@ public void Execute()
/// <returns>Returns <see langword="true"/> if the command can execute,otherwise returns <see langword="false"/>.</returns>
public bool CanExecute()
{
return _canExecuteMethod();
try
{
return _canExecuteMethod();
}
catch (Exception ex)
{
if (!ExceptionHandler.CanHandle(ex))
throw;

ExceptionHandler.Handle(ex, null);

return false;
}
}

/// <summary>
Expand Down Expand Up @@ -100,5 +123,101 @@ public DelegateCommand ObservesCanExecute(Expression<Func<bool>> canExecuteExpre
ObservesPropertyInternal(canExecuteExpression);
return this;
}

/// <summary>
/// Registers an callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand Catch(Action<Exception> @catch)
{
ExceptionHandler.Register<Exception>(@catch);
return this;
}

/// <summary>
/// Registers an callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand Catch(Action<Exception, object> @catch)
{
ExceptionHandler.Register<Exception>(@catch);
return this;
}

/// <summary>
/// Registers an callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <typeparam name="TException">The Exception Type</typeparam>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand Catch<TException>(Action<TException> @catch)
where TException : Exception
{
ExceptionHandler.Register<TException>(@catch);
return this;
}

/// <summary>
/// Registers an callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <typeparam name="TException">The Exception Type</typeparam>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand Catch<TException>(Action<TException, object> @catch)
where TException : Exception
{
ExceptionHandler.Register<TException>(@catch);
return this;
}

/// <summary>
/// Registers an async callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand Catch(Func<Exception, Task> @catch)
{
ExceptionHandler.Register<Exception>(@catch);
return this;
}

/// <summary>
/// Registers an async callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand Catch(Func<Exception, object, Task> @catch)
{
ExceptionHandler.Register<Exception>(@catch);
return this;
}

/// <summary>
/// Registers an async callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <typeparam name="TException">The Exception Type</typeparam>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand Catch<TException>(Func<TException, Task> @catch)
where TException : Exception
{
ExceptionHandler.Register<TException>(@catch);
return this;
}

/// <summary>
/// Registers an async callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <typeparam name="TException">The Exception Type</typeparam>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand Catch<TException>(Func<TException, object, Task> @catch)
where TException : Exception
{
ExceptionHandler.Register<TException>(@catch);
return this;
}
}
}
10 changes: 8 additions & 2 deletions src/Prism.Core/Commands/DelegateCommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq.Expressions;
using System.Threading;
using System.Windows.Input;
using Prism.Common;

namespace Prism.Commands
{
Expand All @@ -17,6 +18,11 @@ public abstract class DelegateCommandBase : ICommand, IActiveAware
private SynchronizationContext _synchronizationContext;
private readonly HashSet<string> _observedPropertiesExpressions = new HashSet<string>();

/// <summary>
/// Provides an Exception Handler to register callbacks or handle encountered exceptions within
/// </summary>
protected readonly MulticastExceptionHandler ExceptionHandler = new MulticastExceptionHandler();

/// <summary>
/// Creates a new instance of a <see cref="DelegateCommandBase"/>, specifying both the execute action and the can execute function.
/// </summary>
Expand All @@ -32,7 +38,7 @@ protected DelegateCommandBase()

/// <summary>
/// Raises <see cref="ICommand.CanExecuteChanged"/> so every
/// command invoker can requery <see cref="ICommand.CanExecute"/>.
/// command invoker can re-query <see cref="ICommand.CanExecute"/>.
/// </summary>
protected virtual void OnCanExecuteChanged()
{
Expand All @@ -48,7 +54,7 @@ protected virtual void OnCanExecuteChanged()

/// <summary>
/// Raises <see cref="CanExecuteChanged"/> so every command invoker
/// can requery to check if the command can execute.
/// can re-query to check if the command can execute.
/// </summary>
/// <remarks>Note that this will trigger the execution of <see cref="CanExecuteChanged"/> once for each invoker.</remarks>
[SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
Expand Down
153 changes: 149 additions & 4 deletions src/Prism.Core/Commands/DelegateCommand{T}.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Input;
using Prism.Properties;

Expand Down Expand Up @@ -79,7 +80,17 @@ public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
///<param name="parameter">Data used by the command.</param>
public void Execute(T parameter)
{
_executeMethod(parameter);
try
{
_executeMethod(parameter);
}
catch (Exception ex)
{
if (!ExceptionHandler.CanHandle(ex))
throw;

ExceptionHandler.Handle(ex, parameter);
}
}

///<summary>
Expand All @@ -91,7 +102,19 @@ public void Execute(T parameter)
///</returns>
public bool CanExecute(T parameter)
{
return _canExecuteMethod(parameter);
try
{
return _canExecuteMethod(parameter);
}
catch (Exception ex)
{
if (!ExceptionHandler.CanHandle(ex))
throw;

ExceptionHandler.Handle(ex, parameter);

return false;
}
}

/// <summary>
Expand All @@ -100,7 +123,19 @@ public bool CanExecute(T parameter)
/// <param name="parameter">Command Parameter</param>
protected override void Execute(object parameter)
{
Execute((T)parameter);
try
{
// Note: We don't call Execute because we would potentially invoke the Try/Catch twice.
// It is also needed here incase (T)parameter throws the exception
_executeMethod((T)parameter);
}
catch (Exception ex)
{
if (!ExceptionHandler.CanHandle(ex))
throw;

ExceptionHandler.Handle(ex, parameter);
}
}

/// <summary>
Expand All @@ -110,7 +145,21 @@ protected override void Execute(object parameter)
/// <returns><see langword="true"/> if the Command Can Execute, otherwise <see langword="false" /></returns>
protected override bool CanExecute(object parameter)
{
return CanExecute((T)parameter);
try
{
// Note: We don't call Execute because we would potentially invoke the Try/Catch twice.
// It is also needed here incase (T)parameter throws the exception
return CanExecute((T)parameter);
}
catch (Exception ex)
{
if (!ExceptionHandler.CanHandle(ex))
throw;

ExceptionHandler.Handle(ex, parameter);

return false;
}
}

/// <summary>
Expand All @@ -137,5 +186,101 @@ public DelegateCommand<T> ObservesCanExecute(Expression<Func<bool>> canExecuteEx
ObservesPropertyInternal(canExecuteExpression);
return this;
}

/// <summary>
/// Registers an callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand<T> Catch(Action<Exception> @catch)
{
ExceptionHandler.Register<Exception>(@catch);
return this;
}

/// <summary>
/// Registers an callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand<T> Catch(Action<Exception, object> @catch)
{
ExceptionHandler.Register<Exception>(@catch);
return this;
}

/// <summary>
/// Registers an callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <typeparam name="TException">The Exception Type</typeparam>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand<T> Catch<TException>(Action<TException> @catch)
where TException : Exception
{
ExceptionHandler.Register<TException>(@catch);
return this;
}

/// <summary>
/// Registers an callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <typeparam name="TException">The Exception Type</typeparam>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand<T> Catch<TException>(Action<TException, object> @catch)
where TException : Exception
{
ExceptionHandler.Register<TException>(@catch);
return this;
}

/// <summary>
/// Registers an async callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand<T> Catch(Func<Exception, Task> @catch)
{
ExceptionHandler.Register<Exception>(@catch);
return this;
}

/// <summary>
/// Registers an async callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand<T> Catch(Func<Exception, object, Task> @catch)
{
ExceptionHandler.Register<Exception>(@catch);
return this;
}

/// <summary>
/// Registers an async callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <typeparam name="TException">The Exception Type</typeparam>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand<T> Catch<TException>(Func<TException, Task> @catch)
where TException : Exception
{
ExceptionHandler.Register<TException>(@catch);
return this;
}

/// <summary>
/// Registers an async callback if an exception is encountered while executing the <see cref="DelegateCommand"/>
/// </summary>
/// <typeparam name="TException">The Exception Type</typeparam>
/// <param name="catch">The Callback</param>
/// <returns>The current instance of <see cref="DelegateCommand"/></returns>
public DelegateCommand<T> Catch<TException>(Func<TException, object, Task> @catch)
where TException : Exception
{
ExceptionHandler.Register<TException>(@catch);
return this;
}
}
}
Loading

0 comments on commit a128f20

Please sign in to comment.