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();
}
}
}