File: CommandMapperExtensions.cs
Web Access
Project: src\src\Core\src\Core.csproj (Microsoft.Maui)
using System;
 
namespace Microsoft.Maui
{
	public static class CommandMapperExtensions
	{
		/// <summary>
		/// Modify a command mapping in place.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The modified method to call when the command is updated.</param>
		public static void ModifyMapping<TVirtualView, TViewHandler>(this CommandMapper<TVirtualView, TViewHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?, Action<IElementHandler, IElement, object?>?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
			=> ((ICommandMapper<TVirtualView, TViewHandler>)commandMapper).ModifyMapping(key, method);
 
		/// <summary>
		/// Modify a command mapping in place.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The modified method to call when the command is updated.</param>
		public static void ModifyMapping<TVirtualView, TViewHandler>(this ICommandMapper<TVirtualView, TViewHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?, Action<IElementHandler, IElement, object?>?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
		{
			var previousMethod = commandMapper.GetCommand(key);
 
			commandMapper.Add(key, newMethod);
 
			void newMethod(TViewHandler handler, TVirtualView view, object? args)
			{
				method(handler, view, args, previousMethod);
			}
		}
 
		/// <summary>
		/// Modify a command mapping in place but call the previous mapping if the types do not match.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The modified method to call when the command is updated.</param>
		public static void ModifyMapping<TVirtualView, TViewHandler>(this ICommandMapper<IElement, IElementHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?, Action<IElementHandler, IElement, object?>?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
		{
			var previousMethod = commandMapper.GetCommand(key);
 
			void newMethod(IElementHandler handler, IElement view, object? args)
			{
				if ((handler is null || handler is TViewHandler) && view is TVirtualView v)
					method((TViewHandler)handler!, v, args, previousMethod);
				else
					previousMethod?.Invoke(handler!, view, args);
			}
 
			commandMapper.Add(key, newMethod);
		}
 
		/// <summary>
		/// Replace a command mapping in place but call the previous mapping if the types do not match.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The modified method to call when the command is updated.</param>
		public static void ReplaceMapping<TVirtualView, TViewHandler>(this ICommandMapper<IElement, IElementHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
		{
			commandMapper.ModifyMapping<TVirtualView, TViewHandler>(key, (h, v, a, p) => method.Invoke(h, v, a));
		}
 
		/// <summary>
		/// Specify a method to be run after an existing command mapping.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The method to call after the existing mapping is finished.</param>
		public static void AppendToMapping<TVirtualView, TViewHandler>(this CommandMapper<TVirtualView, TViewHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
			=> ((ICommandMapper<TVirtualView, TViewHandler>)commandMapper).AppendToMapping(key, method);
 
		/// <summary>
		/// Specify a method to be run after an existing command mapping.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The method to call after the existing mapping is finished.</param>
		public static void AppendToMapping<TVirtualView, TViewHandler>(this ICommandMapper<TVirtualView, TViewHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
		{
			commandMapper.ModifyMapping(key, (handler, view, args, action) =>
			{
				action?.Invoke(handler, view, args);
				method(handler, view, args);
			});
		}
 
		/// <summary>
		/// Specify a method to be run after an existing command mapping but skip if the types do not match.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The method to call after the existing mapping is finished.</param>
		public static void AppendToMapping<TVirtualView, TViewHandler>(this ICommandMapper<IElement, IElementHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
		{
			commandMapper.ModifyMapping(key, (handler, view, args, action) =>
			{
				action?.Invoke(handler, view, args);
 
				if ((handler is null || handler is TViewHandler) && view is TVirtualView v)
					method((TViewHandler)handler!, v, args);
			});
		}
 
		/// <summary>
		/// Specify a method to be run before an existing command mapping.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The method to call before the existing mapping begins.</param>
		public static void PrependToMapping<TVirtualView, TViewHandler>(this CommandMapper<TVirtualView, TViewHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
			=> ((ICommandMapper<TVirtualView, TViewHandler>)commandMapper).PrependToMapping(key, method);
 
		/// <summary>
		/// Specify a method to be run before an existing command mapping.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The method to call before the existing mapping begins.</param>
		public static void PrependToMapping<TVirtualView, TViewHandler>(this ICommandMapper<TVirtualView, TViewHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
		{
			commandMapper.ModifyMapping(key, (handler, view, args, action) =>
			{
				method(handler, view, args);
				action?.Invoke(handler, view, args);
			});
		}
 
		/// <summary>
		/// Specify a method to be run before an existing command mapping but skip if the types do not match.
		/// </summary>
		/// <typeparam name="TVirtualView">The cross-platform type.</typeparam>
		/// <typeparam name="TViewHandler">The handler type.</typeparam>
		/// <param name="commandMapper">The command mapper in which to change the mapping.</param>
		/// <param name="key">The name of the command.</param>
		/// <param name="method">The method to call before the existing mapping begins.</param>
		public static void PrependToMapping<TVirtualView, TViewHandler>(this ICommandMapper<IElement, IElementHandler> commandMapper,
			string key, Action<TViewHandler, TVirtualView, object?> method)
			where TVirtualView : IElement where TViewHandler : IElementHandler
		{
			commandMapper.ModifyMapping(key, (handler, view, args, action) =>
			{
				if ((handler is null || handler is TViewHandler) && view is TVirtualView v)
					method((TViewHandler)handler!, v, args);
 
				action?.Invoke(handler!, view, args);
			});
		}
	}
}