mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-08 02:06:40 +08:00
整理整理
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="ICommand"/> whose delegates can be attached for <see cref="Execute(T)"/> and <see cref="CanExecute(T)"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Parameter type.</typeparam>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// <para/>
|
||||
/// Instead, callers should support a value type by using a nullable value type and checking the HasValue property before using the Value property.
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public MyClass()
|
||||
/// {
|
||||
/// this.submitCommand = new DelegateCommand<int?>(this.Submit, this.CanSubmit);
|
||||
/// }
|
||||
///
|
||||
/// private bool CanSubmit(int? customerId)
|
||||
/// {
|
||||
/// return (customerId.HasValue && customers.Contains(customerId.Value));
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public class DelegateCommand<T> : DelegateCommandBase
|
||||
{
|
||||
readonly Action<T> _executeMethod;
|
||||
Func<T, bool> _canExecuteMethod;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="executeMethod">Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.</param>
|
||||
/// <remarks><see cref="CanExecute(T)"/> will always return true.</remarks>
|
||||
public DelegateCommand(Action<T> executeMethod)
|
||||
: this(executeMethod, (o) => true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="executeMethod">Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.</param>
|
||||
/// <param name="canExecuteMethod">Delegate to execute when CanExecute is called on the command. This can be null.</param>
|
||||
/// <exception cref="ArgumentNullException">When both <paramref name="executeMethod"/> and <paramref name="canExecuteMethod"/> are <see langword="null" />.</exception>
|
||||
public DelegateCommand(Action<T> executeMethod, Func<T, bool> 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;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Executes the command and invokes the <see cref="Action{T}"/> provided during construction.
|
||||
///</summary>
|
||||
///<param name="parameter">Data used by the command.</param>
|
||||
public void Execute(T parameter)
|
||||
{
|
||||
_executeMethod(parameter);
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Determines if the command can execute by invoked the <see cref="Func{T,Bool}"/> provided during construction.
|
||||
///</summary>
|
||||
///<param name="parameter">Data used by the command to determine if it can execute.</param>
|
||||
///<returns>
|
||||
///<see langword="true" /> if this command can be executed; otherwise, <see langword="false" />.
|
||||
///</returns>
|
||||
public bool CanExecute(T parameter)
|
||||
{
|
||||
return _canExecuteMethod(parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the internal invocation of <see cref="ICommand.Execute(object)"/>
|
||||
/// </summary>
|
||||
/// <param name="parameter">Command Parameter</param>
|
||||
protected override void Execute(object parameter)
|
||||
{
|
||||
Execute((T)parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the internal invocation of <see cref="ICommand.CanExecute(object)"/>
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
/// <returns><see langword="true"/> if the Command Can Execute, otherwise <see langword="false" /></returns>
|
||||
protected override bool CanExecute(object parameter)
|
||||
{
|
||||
return CanExecute((T)parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The type of the return value of the method that this delegate encapulates</typeparam>
|
||||
/// <param name="propertyExpression">The property expression. Example: ObservesProperty(() => PropertyName).</param>
|
||||
/// <returns>The current instance of DelegateCommand</returns>
|
||||
public DelegateCommand<T> ObservesProperty<TType>(Expression<Func<TType>> propertyExpression)
|
||||
{
|
||||
ObservesPropertyInternal(propertyExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="canExecuteExpression">The property expression. Example: ObservesCanExecute(() => PropertyName).</param>
|
||||
/// <returns>The current instance of DelegateCommand</returns>
|
||||
public DelegateCommand<T> ObservesCanExecute(Expression<Func<bool>> canExecuteExpression)
|
||||
{
|
||||
Expression<Func<T, bool>> expression = System.Linq.Expressions.Expression.Lambda<Func<T, bool>>(canExecuteExpression.Body, System.Linq.Expressions.Expression.Parameter(typeof(T), "o"));
|
||||
_canExecuteMethod = expression.Compile();
|
||||
ObservesPropertyInternal(canExecuteExpression);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user