自定义委托命令DelegateCommand

DelegateCommand:

public class DelegateCommand : DelegateCommandBase
{
    private Action _executeMethod;

    private Func<bool> _canExecuteMethod;

    public DelegateCommand(Action executeMethod)
        : this(executeMethod, () => true)
    {
    }

    public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
    {
        if (executeMethod == null || canExecuteMethod == null)
        {
            throw new ArgumentNullException("executeMethod", "DelegateCommandDelegatesCannotBeNull");
        }

        _executeMethod = executeMethod;
        _canExecuteMethod = canExecuteMethod;
    }

    public void Execute()
    {
        _executeMethod();
    }

    public bool CanExecute()
    {
        return _canExecuteMethod();
    }

    protected override void Execute(object parameter)
    {
        Execute();
    }

    protected override bool CanExecute(object parameter)
    {
        return CanExecute();
    }

    public DelegateCommand ObservesProperty<T>(Expression<Func<T>> propertyExpression)
    {
        ObservesPropertyInternal(propertyExpression);
        return this;
    }

    public DelegateCommand ObservesCanExecute(Expression<Func<bool>> canExecuteExpression)
    {
        _canExecuteMethod = canExecuteExpression.Compile();
        ObservesPropertyInternal(canExecuteExpression);
        return this;
    }
}

DelegateCommand

public class DelegateCommand<T> : DelegateCommandBase
{
    private readonly Action<T> _executeMethod;

    private Func<T, bool> _canExecuteMethod;

    public DelegateCommand(Action<T> executeMethod)
        : this(executeMethod, (Func<T, bool>)((T o) => true))
    {
    }

    public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
    {
        if (executeMethod == null || canExecuteMethod == null)
        {
            throw new ArgumentNullException("executeMethod", "DelegateCommandDelegatesCannotBeNull");
        }

        TypeInfo typeInfo = typeof(T).GetTypeInfo();
        if (typeInfo.IsValueType && (!typeInfo.IsGenericType || !typeof(Nullable<>).GetTypeInfo().IsAssignableFrom(typeInfo.GetGenericTypeDefinition().GetTypeInfo())))
        {
            throw new InvalidCastException("DelegateCommandInvalidGenericPayloadType");
        }

        _executeMethod = executeMethod;
        _canExecuteMethod = canExecuteMethod;
    }

    public void Execute(T parameter)
    {
        _executeMethod(parameter);
    }

    public bool CanExecute(T parameter)
    {
        return _canExecuteMethod(parameter);
    }

    protected override void Execute(object parameter)
    {
        Execute((T)parameter);
    }

    protected override bool CanExecute(object parameter)
    {
        return CanExecute((T)parameter);
    }

    public DelegateCommand<T> ObservesProperty<TType>(Expression<Func<TType>> propertyExpression)
    {
        ObservesPropertyInternal(propertyExpression);
        return this;
    }

    public DelegateCommand<T> ObservesCanExecute(Expression<Func<bool>> canExecuteExpression)
    {
        Expression<Func<T, bool>> expression = Expression.Lambda<Func<T, bool>>(canExecuteExpression.Body, new ParameterExpression[1] { Expression.Parameter(typeof(T), "o") });
        _canExecuteMethod = expression.Compile();
        ObservesPropertyInternal(canExecuteExpression);
        return this;
    }
}

DelegateCommandBase:

    public abstract class DelegateCommandBase : ICommand, IActiveAware
    {
    private bool _isActive;

    private SynchronizationContext _synchronizationContext;

    private readonly HashSet<string> _observedPropertiesExpressions = new HashSet<string>();

    public bool IsActive
    {
        get
        {
            return _isActive;
        }
        set
        {
            if (_isActive != value)
            {
                _isActive = value;
                OnIsActiveChanged();
            }
        }
    }

    public virtual event EventHandler CanExecuteChanged;

    public virtual event EventHandler IsActiveChanged;

    protected DelegateCommandBase()
    {
        _synchronizationContext = SynchronizationContext.Current;
    }

    protected virtual void OnCanExecuteChanged()
    {
        EventHandler handler = this.CanExecuteChanged;
        if (handler == null)
        {
            return;
        }

        if (_synchronizationContext != null && _synchronizationContext != SynchronizationContext.Current)
        {
            _synchronizationContext.Post(delegate
            {
                handler(this, EventArgs.Empty);
            }, null);
        }
        else
        {
            handler(this, EventArgs.Empty);
        }
    }

    public void RaiseCanExecuteChanged()
    {
        OnCanExecuteChanged();
    }

    void ICommand.Execute(object parameter)
    {
        Execute(parameter);
    }

    bool ICommand.CanExecute(object parameter)
    {
        return CanExecute(parameter);
    }

    protected abstract void Execute(object parameter);

    protected abstract bool CanExecute(object parameter);

    protected internal void ObservesPropertyInternal<T>(Expression<Func<T>> propertyExpression)
    {
        if (_observedPropertiesExpressions.Contains(propertyExpression.ToString()))
        {
            throw new ArgumentException(propertyExpression.ToString() + " is already being observed.", "propertyExpression");
        }

        _observedPropertiesExpressions.Add(propertyExpression.ToString());
        PropertyObserver.Observes(propertyExpression, RaiseCanExecuteChanged);
    }

    protected virtual void OnIsActiveChanged()
    {
        this.IsActiveChanged?.Invoke(this, EventArgs.Empty);
    }
}

IActiveAware:

public interface IActiveAware
{
  bool IsActive { get; set; }

  event EventHandler IsActiveChanged;
}

PropertyObserver:

 internal class PropertyObserver
 {
     private readonly Action _action;
 
     private PropertyObserver(Expression propertyExpression, Action action)
     {
         _action = action;
         SubscribeListeners(propertyExpression);
     }
 
     private void SubscribeListeners(Expression propertyExpression)
     {
         Stack<PropertyInfo> stack = new Stack<PropertyInfo>();
         while (propertyExpression is MemberExpression memberExpression)
         {
             propertyExpression = memberExpression.Expression;
             stack.Push(memberExpression.Member as PropertyInfo);
         }
 
         if (!(propertyExpression is ConstantExpression constantExpression))
         {
             throw new NotSupportedException("Operation not supported for the given expression type. Only MemberExpression and ConstantExpression are currently supported.");
         }
 
         PropertyObserverNode propertyObserverNode = new PropertyObserverNode(stack.Pop(), _action);
         PropertyObserverNode propertyObserverNode2 = propertyObserverNode;
         using (Stack<PropertyInfo>.Enumerator enumerator = stack.GetEnumerator())
         {
             while (enumerator.MoveNext())
             {
                 PropertyObserverNode propertyObserverNode4 = (propertyObserverNode2.Next = new PropertyObserverNode(enumerator.Current, _action));
                 propertyObserverNode2 = propertyObserverNode4;
             }
         }
 
         if (!(constantExpression.Value is INotifyPropertyChanged inpcObject))
         {
             throw new InvalidOperationException("Trying to subscribe PropertyChanged listener in object that owns '" + propertyObserverNode.PropertyInfo.Name + "' property, but the object does not implements INotifyPropertyChanged.");
         }
 
         propertyObserverNode.SubscribeListenerFor(inpcObject);
     }
 
     internal static PropertyObserver Observes<T>(Expression<Func<T>> propertyExpression, Action action)
     {
         return new PropertyObserver(propertyExpression.Body, action);
     }
 }
 
 internal class PropertyObserverNode
 {
     private readonly Action _action;
 
     private INotifyPropertyChanged _inpcObject;
 
     public PropertyInfo PropertyInfo { get; }
 
     public PropertyObserverNode Next { get; set; }
 
     public PropertyObserverNode(PropertyInfo propertyInfo, Action action)
     {
         PropertyObserverNode propertyObserverNode = this;
         PropertyInfo = propertyInfo ?? throw new ArgumentNullException("propertyInfo");
         _action = delegate
         {
             action?.Invoke();
             if (propertyObserverNode.Next != null)
             {
                 propertyObserverNode.Next.UnsubscribeListener();
                 propertyObserverNode.GenerateNextNode();
             }
         };
     }
 
     public void SubscribeListenerFor(INotifyPropertyChanged inpcObject)
     {
         _inpcObject = inpcObject;
         _inpcObject.PropertyChanged += OnPropertyChanged;
         if (Next != null)
         {
             GenerateNextNode();
         }
     }
 
     private void GenerateNextNode()
     {
         object value = PropertyInfo.GetValue(_inpcObject);
         if (value != null)
         {
             if (!(value is INotifyPropertyChanged inpcObject))
             {
                 throw new InvalidOperationException("Trying to subscribe PropertyChanged listener in object that owns '" + Next.PropertyInfo.Name + "' property, but the object does not implements INotifyPropertyChanged.");
             }
 
             Next.SubscribeListenerFor(inpcObject);
         }
     }
 
     private void UnsubscribeListener()
     {
         if (_inpcObject != null)
         {
             _inpcObject.PropertyChanged -= OnPropertyChanged;
         }
 
         Next?.UnsubscribeListener();
     }
 
     private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
     {
         if (e?.PropertyName == PropertyInfo.Name || e == null || e.PropertyName == null)
         {
             _action?.Invoke();
         }
     }
 }
posted @ 2025-06-16 14:21  叶落轻风雨  阅读(51)  评论(0)    收藏  举报