Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// <summary>
- /// This class allows delegating the commanding logic to methods passed as parameters,
- /// and enables a View to bind commands to objects that are not part of the element tree.
- /// </summary>
- public class RelayCommand : ICommand
- {
- private readonly Func<bool>? _canExecuteMethod;
- private readonly Action _executeMethod;
- private List<WeakReference>? _canExecuteChangedHandlers;
- private readonly bool _isAutomaticRequeryEnabled;
- #region Constructors
- public RelayCommand(Action executeMethod)
- : this(executeMethod, null!, false)
- {
- }
- public RelayCommand(Action executeMethod, Func<bool> canExecuteMethod, bool isAutomaticRequeryEnabled = true)
- {
- _executeMethod = executeMethod ?? throw new ArgumentNullException(nameof(executeMethod));
- _canExecuteMethod = canExecuteMethod;
- _isAutomaticRequeryEnabled = isAutomaticRequeryEnabled;
- }
- #endregion
- #region Public Methods
- public RelayCommand DependFrom(INotifyPropertyChanged propertySource, params string[] props)
- {
- foreach (var propertyName in props)
- PropertyChangedEventManager.AddHandler(propertySource, PropertyChangedHandler, propertyName);
- return this;
- }
- private void PropertyChangedHandler(object? sender, PropertyChangedEventArgs e)
- {
- RaiseCanExecuteChanged();
- }
- /// <summary>
- /// Method to determine if the command can be executed
- /// </summary>
- public bool CanExecute()
- {
- if (_canExecuteMethod != null)
- return _canExecuteMethod();
- return true;
- }
- /// <summary>
- /// Execution of the command
- /// </summary>
- public void Execute()
- {
- _executeMethod?.Invoke();
- }
- /// <summary>
- /// Raises the CanExecuteChaged event
- /// </summary>
- public void RaiseCanExecuteChanged()
- {
- OnCanExecuteChanged();
- }
- /// <summary>
- /// Protected virtual method to raise CanExecuteChanged event
- /// </summary>
- protected virtual void OnCanExecuteChanged()
- {
- CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
- }
- #endregion
- #region ICommand Members
- /// <summary>
- /// ICommand.CanExecuteChanged implementation
- /// </summary>
- public event EventHandler? CanExecuteChanged
- {
- add
- {
- if (_canExecuteMethod == null)
- return;
- if (_isAutomaticRequeryEnabled)
- CommandManager.RequerySuggested += value;
- CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
- }
- remove
- {
- if (_canExecuteMethod == null)
- return;
- if (_isAutomaticRequeryEnabled)
- CommandManager.RequerySuggested -= value;
- CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
- }
- }
- bool ICommand.CanExecute(object? parameter) => CanExecute();
- void ICommand.Execute(object? parameter) => Execute();
- #endregion
- }
- /// <summary>
- /// This class allows delegating the commanding logic to methods passed as parameters,
- /// and enables a View to bind commands to objects that are not part of the element tree.
- /// </summary>
- /// <typeparam name="T">Type of the parameter passed to the delegates</typeparam>
- public class RelayCommand<T> : ICommand
- {
- private readonly Func<T, bool>? _canExecuteMethod;
- private readonly Action<T> _executeMethod;
- private List<WeakReference>? _canExecuteChangedHandlers;
- private readonly bool _isAutomaticRequeryEnabled;
- #region Constructors
- public RelayCommand(Action<T> executeMethod)
- : this(executeMethod, null!, false)
- {
- }
- /// <summary>
- /// Constructor
- /// </summary>
- public RelayCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod,
- bool isAutomaticRequeryEnabled = true)
- {
- _executeMethod = executeMethod ?? throw new ArgumentNullException(nameof(executeMethod));
- _canExecuteMethod = canExecuteMethod;
- _isAutomaticRequeryEnabled = isAutomaticRequeryEnabled;
- }
- #endregion
- #region Public Methods
- public RelayCommand<T> DependFrom(INotifyPropertyChanged propertySource, params string[] props)
- {
- foreach (var propertyName in props)
- PropertyChangedEventManager.AddHandler(propertySource, PropertyChangedHandler, propertyName);
- return this;
- }
- private void PropertyChangedHandler(object? sender, PropertyChangedEventArgs e)
- {
- RaiseCanExecuteChanged();
- }
- /// <summary>
- /// Method to determine if the command can be executed
- /// </summary>
- public bool CanExecute(T parameter)
- {
- if (_canExecuteMethod != null)
- return _canExecuteMethod(parameter);
- return true;
- }
- /// <summary>
- /// Execution of the command
- /// </summary>
- public void Execute(T parameter)
- {
- _executeMethod?.Invoke(parameter);
- }
- /// <summary>
- /// Raises the CanExecuteChaged event
- /// </summary>
- public void RaiseCanExecuteChanged()
- {
- OnCanExecuteChanged();
- }
- /// <summary>
- /// Protected virtual method to raise CanExecuteChanged event
- /// </summary>
- protected virtual void OnCanExecuteChanged()
- {
- CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
- }
- #endregion
- #region ICommand Members
- /// <summary>
- /// ICommand.CanExecuteChanged implementation
- /// </summary>
- public event EventHandler? CanExecuteChanged
- {
- add
- {
- if (_canExecuteMethod == null)
- return;
- if (_isAutomaticRequeryEnabled)
- CommandManager.RequerySuggested += value;
- CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value!, 2);
- }
- remove
- {
- if (_canExecuteMethod == null)
- return;
- if (_isAutomaticRequeryEnabled)
- CommandManager.RequerySuggested -= value;
- CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value!);
- }
- }
- bool ICommand.CanExecute(object? parameter)
- {
- // if T is of value type and the parameter is not
- // set yet, then return false if CanExecute delegate
- // exists, else return true
- if (parameter == null &&
- typeof(T).IsValueType)
- return _canExecuteMethod == null;
- return CanExecute((T)parameter!);
- }
- void ICommand.Execute(object? parameter)
- {
- Execute((T)parameter!);
- }
- #endregion
- }
- /// <summary>
- /// This class contains methods for the CommandManager that help avoid memory leaks by
- /// using weak references.
- /// </summary>
- internal class CommandManagerHelper
- {
- internal static void CallWeakReferenceHandlers(List<WeakReference>? handlers)
- {
- if (handlers != null)
- {
- // Take a snapshot of the handlers before we call out to them since the handlers
- // could cause the array to me modified while we are reading it.
- var callees = new EventHandler[handlers.Count];
- var count = 0;
- for (var i = handlers.Count - 1; i >= 0; i--)
- {
- var reference = handlers[i];
- if (reference.Target is EventHandler handler)
- {
- callees[count] = handler;
- count++;
- }
- else
- {
- // Clean up old handlers that have been collected
- handlers.RemoveAt(i);
- }
- }
- // Call the handlers that we snapshotted
- for (var i = 0; i < count; i++)
- {
- var handler = callees[i];
- handler(null, EventArgs.Empty);
- }
- }
- }
- internal static void AddWeakReferenceHandler(ref List<WeakReference>? handlers, EventHandler handler,
- int defaultListSize)
- {
- handlers ??= defaultListSize > 0 ? new List<WeakReference>(defaultListSize) : new List<WeakReference>();
- handlers.Add(new WeakReference(handler));
- }
- internal static void RemoveWeakReferenceHandler(List<WeakReference>? handlers, EventHandler handler)
- {
- if (handlers != null)
- for (var i = handlers.Count - 1; i >= 0; i--)
- {
- var reference = handlers[i];
- if (!(reference.Target is EventHandler existingHandler) || existingHandler == handler)
- handlers.RemoveAt(i);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement