using System; using System.Linq.Expressions; using System.Reflection; using System.Windows.Input; namespace AIStudio.Wpf.DiagramDesigner.Additionals.Commands { /// /// An whose delegates can be attached for and . /// /// Parameter type. /// /// The constructor deliberately prevents the use of value types. /// Because ICommand takes an object, having a value type for T would cause unexpected behavior when CanExecute(null) is called during XAML initialization for command bindings. /// Using default(T) was considered and rejected as a solution because the implementor would not be able to distinguish between a valid and defaulted values. /// /// Instead, callers should support a value type by using a nullable value type and checking the HasValue property before using the Value property. /// /// /// public MyClass() /// { /// this.submitCommand = new DelegateCommand<int?>(this.Submit, this.CanSubmit); /// } /// /// private bool CanSubmit(int? customerId) /// { /// return (customerId.HasValue && customers.Contains(customerId.Value)); /// } /// /// /// public class DelegateCommand : DelegateCommandBase { readonly Action _executeMethod; Func _canExecuteMethod; /// /// Initializes a new instance of . /// /// Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate. /// will always return true. public DelegateCommand(Action executeMethod) : this(executeMethod, (o) => true) { } /// /// Initializes a new instance of . /// /// Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate. /// Delegate to execute when CanExecute is called on the command. This can be null. /// When both and are . public DelegateCommand(Action executeMethod, Func canExecuteMethod) : base() { if (executeMethod == null || canExecuteMethod == null) throw new ArgumentNullException(nameof(executeMethod), "DelegateCommandDelegatesCannotBeNull"); TypeInfo genericTypeInfo = typeof(T).GetTypeInfo(); // DelegateCommand allows object or Nullable<>. // note: Nullable<> is a struct so we cannot use a class constraint. if (genericTypeInfo.IsValueType) { if ((!genericTypeInfo.IsGenericType) || (!typeof(Nullable<>).GetTypeInfo().IsAssignableFrom(genericTypeInfo.GetGenericTypeDefinition().GetTypeInfo()))) { throw new InvalidCastException("DelegateCommandInvalidGenericPayloadType"); } } _executeMethod = executeMethod; _canExecuteMethod = canExecuteMethod; } /// ///Executes the command and invokes the provided during construction. /// ///Data used by the command. public void Execute(T parameter) { _executeMethod(parameter); } /// ///Determines if the command can execute by invoked the provided during construction. /// ///Data used by the command to determine if it can execute. /// /// if this command can be executed; otherwise, . /// public bool CanExecute(T parameter) { return _canExecuteMethod(parameter); } /// /// Handle the internal invocation of /// /// Command Parameter protected override void Execute(object parameter) { Execute((T)parameter); } /// /// Handle the internal invocation of /// /// /// if the Command Can Execute, otherwise protected override bool CanExecute(object parameter) { return CanExecute((T)parameter); } /// /// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications. /// /// The type of the return value of the method that this delegate encapulates /// The property expression. Example: ObservesProperty(() => PropertyName). /// The current instance of DelegateCommand public DelegateCommand ObservesProperty(Expression> propertyExpression) { ObservesPropertyInternal(propertyExpression); return this; } /// /// Observes a property that is used to determine if this command can execute, and if it implements INotifyPropertyChanged it will automatically call DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications. /// /// The property expression. Example: ObservesCanExecute(() => PropertyName). /// The current instance of DelegateCommand public DelegateCommand ObservesCanExecute(Expression> canExecuteExpression) { Expression> expression = System.Linq.Expressions.Expression.Lambda>(canExecuteExpression.Body, System.Linq.Expressions.Expression.Parameter(typeof(T), "o")); _canExecuteMethod = expression.Compile(); ObservesPropertyInternal(canExecuteExpression); return this; } } }