Advertisement
Guest User

Untitled

a guest
Jul 5th, 2022
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.93 KB | None | 0 0
  1.   /// <summary>
  2.     ///     This class allows delegating the commanding logic to methods passed as parameters,
  3.     ///     and enables a View to bind commands to objects that are not part of the element tree.
  4.     /// </summary>
  5.     public class RelayCommand : ICommand
  6.     {
  7.         private readonly Func<bool>? _canExecuteMethod;
  8.         private readonly Action _executeMethod;
  9.         private List<WeakReference>? _canExecuteChangedHandlers;
  10.         private readonly bool _isAutomaticRequeryEnabled;
  11.  
  12.         #region Constructors
  13.  
  14.         public RelayCommand(Action executeMethod)
  15.             : this(executeMethod, null!, false)
  16.         {
  17.         }
  18.  
  19.         public RelayCommand(Action executeMethod, Func<bool> canExecuteMethod, bool isAutomaticRequeryEnabled = true)
  20.         {
  21.             _executeMethod = executeMethod ?? throw new ArgumentNullException(nameof(executeMethod));
  22.             _canExecuteMethod = canExecuteMethod;
  23.             _isAutomaticRequeryEnabled = isAutomaticRequeryEnabled;
  24.         }
  25.  
  26.         #endregion
  27.  
  28.         #region Public Methods
  29.  
  30.         public RelayCommand DependFrom(INotifyPropertyChanged propertySource, params string[] props)
  31.         {
  32.             foreach (var propertyName in props)
  33.                 PropertyChangedEventManager.AddHandler(propertySource, PropertyChangedHandler, propertyName);
  34.             return this;
  35.         }
  36.  
  37.         private void PropertyChangedHandler(object? sender, PropertyChangedEventArgs e)
  38.         {
  39.             RaiseCanExecuteChanged();
  40.         }
  41.  
  42.  
  43.         /// <summary>
  44.         ///     Method to determine if the command can be executed
  45.         /// </summary>
  46.         public bool CanExecute()
  47.         {
  48.             if (_canExecuteMethod != null)
  49.                 return _canExecuteMethod();
  50.             return true;
  51.         }
  52.  
  53.         /// <summary>
  54.         ///     Execution of the command
  55.         /// </summary>
  56.         public void Execute()
  57.         {
  58.             _executeMethod?.Invoke();
  59.         }
  60.  
  61.         /// <summary>
  62.         ///     Raises the CanExecuteChaged event
  63.         /// </summary>
  64.         public void RaiseCanExecuteChanged()
  65.         {
  66.             OnCanExecuteChanged();
  67.         }
  68.  
  69.         /// <summary>
  70.         ///     Protected virtual method to raise CanExecuteChanged event
  71.         /// </summary>
  72.         protected virtual void OnCanExecuteChanged()
  73.         {
  74.             CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
  75.         }
  76.  
  77.         #endregion
  78.  
  79.         #region ICommand Members
  80.  
  81.         /// <summary>
  82.         ///     ICommand.CanExecuteChanged implementation
  83.         /// </summary>
  84.         public event EventHandler? CanExecuteChanged
  85.         {
  86.             add
  87.             {
  88.                 if (_canExecuteMethod == null)
  89.                     return;
  90.  
  91.                 if (_isAutomaticRequeryEnabled)
  92.                     CommandManager.RequerySuggested += value;
  93.                 CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
  94.             }
  95.             remove
  96.             {
  97.                 if (_canExecuteMethod == null)
  98.                     return;
  99.  
  100.                 if (_isAutomaticRequeryEnabled)
  101.                     CommandManager.RequerySuggested -= value;
  102.                 CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
  103.             }
  104.         }
  105.  
  106.         bool ICommand.CanExecute(object? parameter) => CanExecute();
  107.  
  108.         void ICommand.Execute(object? parameter) => Execute();
  109.  
  110.         #endregion
  111.     }
  112.  
  113.     /// <summary>
  114.     ///     This class allows delegating the commanding logic to methods passed as parameters,
  115.     ///     and enables a View to bind commands to objects that are not part of the element tree.
  116.     /// </summary>
  117.     /// <typeparam name="T">Type of the parameter passed to the delegates</typeparam>
  118.     public class RelayCommand<T> : ICommand
  119.     {
  120.         private readonly Func<T, bool>? _canExecuteMethod;
  121.         private readonly Action<T> _executeMethod;
  122.         private List<WeakReference>? _canExecuteChangedHandlers;
  123.         private readonly bool _isAutomaticRequeryEnabled;
  124.  
  125.         #region Constructors
  126.  
  127.         public RelayCommand(Action<T> executeMethod)
  128.             : this(executeMethod, null!, false)
  129.         {
  130.         }
  131.  
  132.         /// <summary>
  133.         ///     Constructor
  134.         /// </summary>
  135.         public RelayCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod,
  136.             bool isAutomaticRequeryEnabled = true)
  137.         {
  138.             _executeMethod = executeMethod ?? throw new ArgumentNullException(nameof(executeMethod));
  139.             _canExecuteMethod = canExecuteMethod;
  140.             _isAutomaticRequeryEnabled = isAutomaticRequeryEnabled;
  141.         }
  142.  
  143.         #endregion
  144.  
  145.         #region Public Methods
  146.        
  147.         public RelayCommand<T> DependFrom(INotifyPropertyChanged propertySource, params string[] props)
  148.         {
  149.             foreach (var propertyName in props)
  150.                 PropertyChangedEventManager.AddHandler(propertySource, PropertyChangedHandler, propertyName);
  151.             return this;
  152.         }
  153.  
  154.         private void PropertyChangedHandler(object? sender, PropertyChangedEventArgs e)
  155.         {
  156.             RaiseCanExecuteChanged();
  157.         }
  158.  
  159.         /// <summary>
  160.         ///     Method to determine if the command can be executed
  161.         /// </summary>
  162.         public bool CanExecute(T parameter)
  163.         {
  164.             if (_canExecuteMethod != null)
  165.                 return _canExecuteMethod(parameter);
  166.             return true;
  167.         }
  168.  
  169.         /// <summary>
  170.         ///     Execution of the command
  171.         /// </summary>
  172.         public void Execute(T parameter)
  173.         {
  174.             _executeMethod?.Invoke(parameter);
  175.         }
  176.  
  177.         /// <summary>
  178.         ///     Raises the CanExecuteChaged event
  179.         /// </summary>
  180.         public void RaiseCanExecuteChanged()
  181.         {
  182.             OnCanExecuteChanged();
  183.         }
  184.  
  185.         /// <summary>
  186.         ///     Protected virtual method to raise CanExecuteChanged event
  187.         /// </summary>
  188.         protected virtual void OnCanExecuteChanged()
  189.         {
  190.             CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
  191.         }
  192.  
  193.         #endregion
  194.  
  195.         #region ICommand Members
  196.  
  197.         /// <summary>
  198.         ///     ICommand.CanExecuteChanged implementation
  199.         /// </summary>
  200.         public event EventHandler? CanExecuteChanged
  201.         {
  202.             add
  203.             {
  204.                 if (_canExecuteMethod == null)
  205.                     return;
  206.  
  207.                 if (_isAutomaticRequeryEnabled)
  208.                     CommandManager.RequerySuggested += value;
  209.                 CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value!, 2);
  210.             }
  211.             remove
  212.             {
  213.                 if (_canExecuteMethod == null)
  214.                     return;
  215.  
  216.                 if (_isAutomaticRequeryEnabled)
  217.                     CommandManager.RequerySuggested -= value;
  218.                 CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value!);
  219.             }
  220.         }
  221.  
  222.         bool ICommand.CanExecute(object? parameter)
  223.         {
  224.             // if T is of value type and the parameter is not
  225.             // set yet, then return false if CanExecute delegate
  226.             // exists, else return true
  227.  
  228.             if (parameter == null &&
  229.                 typeof(T).IsValueType)
  230.                 return _canExecuteMethod == null;
  231.  
  232.             return CanExecute((T)parameter!);
  233.         }
  234.  
  235.         void ICommand.Execute(object? parameter)
  236.         {
  237.             Execute((T)parameter!);
  238.         }
  239.  
  240.         #endregion
  241.     }
  242.  
  243.     /// <summary>
  244.     ///     This class contains methods for the CommandManager that help avoid memory leaks by
  245.     ///     using weak references.
  246.     /// </summary>
  247.     internal class CommandManagerHelper
  248.     {
  249.         internal static void CallWeakReferenceHandlers(List<WeakReference>? handlers)
  250.         {
  251.             if (handlers != null)
  252.             {
  253.                 // Take a snapshot of the handlers before we call out to them since the handlers
  254.                 // could cause the array to me modified while we are reading it.
  255.  
  256.                 var callees = new EventHandler[handlers.Count];
  257.                 var count = 0;
  258.  
  259.                 for (var i = handlers.Count - 1; i >= 0; i--)
  260.                 {
  261.                     var reference = handlers[i];
  262.                     if (reference.Target is EventHandler handler)
  263.                     {
  264.                         callees[count] = handler;
  265.                         count++;
  266.                     }
  267.                     else
  268.                     {
  269.                         // Clean up old handlers that have been collected
  270.                         handlers.RemoveAt(i);
  271.                     }
  272.                 }
  273.  
  274.                 // Call the handlers that we snapshotted
  275.                 for (var i = 0; i < count; i++)
  276.                 {
  277.                     var handler = callees[i];
  278.                     handler(null, EventArgs.Empty);
  279.                 }
  280.             }
  281.         }
  282.  
  283.         internal static void AddWeakReferenceHandler(ref List<WeakReference>? handlers, EventHandler handler,
  284.             int defaultListSize)
  285.         {
  286.             handlers ??= defaultListSize > 0 ? new List<WeakReference>(defaultListSize) : new List<WeakReference>();
  287.  
  288.             handlers.Add(new WeakReference(handler));
  289.         }
  290.  
  291.         internal static void RemoveWeakReferenceHandler(List<WeakReference>? handlers, EventHandler handler)
  292.         {
  293.             if (handlers != null)
  294.                 for (var i = handlers.Count - 1; i >= 0; i--)
  295.                 {
  296.                     var reference = handlers[i];
  297.                     if (!(reference.Target is EventHandler existingHandler) || existingHandler == handler)
  298.                         handlers.RemoveAt(i);
  299.                 }
  300.         }
  301.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement