using Microsoft.Xaml.Behaviors; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Data; using System.Windows.Input; using System.Windows; namespace PDF_Office.Helper { public class CompositeCommandParameter { public CompositeCommandParameter(EventArgs eventArgs, object parameter) { EventArgs = eventArgs; Parameter = parameter; } public EventArgs EventArgs { get; } public object Parameter { get; } } public sealed class AdvancedInvokeCommandAction : TriggerAction<DependencyObject> { private string commandName; public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(AdvancedInvokeCommandAction), null); public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(AdvancedInvokeCommandAction), null); public static readonly DependencyProperty EventArgsConverterProperty = DependencyProperty.Register("EventArgsConverter", typeof(IValueConverter), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null)); public static readonly DependencyProperty EventArgsConverterParameterProperty = DependencyProperty.Register("EventArgsConverterParameter", typeof(object), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null)); public static readonly DependencyProperty EventArgsParameterPathProperty = DependencyProperty.Register("EventArgsParameterPath", typeof(string), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null)); /// <summary> /// Gets or sets the name of the command this action should invoke. /// </summary> /// <value>The name of the command this action should invoke.</value> /// <remarks>This property will be superseded by the Command property if both are set.</remarks> public string CommandName { get { this.ReadPreamble(); return this.commandName; } set { if (this.CommandName != value) { this.WritePreamble(); this.commandName = value; this.WritePostscript(); } } } /// <summary> /// Gets or sets the command this action should invoke. This is a dependency property. /// </summary> /// <value>The command to execute.</value> /// <remarks>This property will take precedence over the CommandName property if both are set.</remarks> public ICommand Command { get { return (ICommand)this.GetValue(CommandProperty); } set { this.SetValue(CommandProperty, value); } } /// <summary> /// Gets or sets the command parameter. This is a dependency property. /// </summary> /// <value>The command parameter.</value> /// <remarks>This is the value passed to ICommand.CanExecute and ICommand.Execute.</remarks> public object CommandParameter { get { return this.GetValue(AdvancedInvokeCommandAction.CommandParameterProperty); } set { this.SetValue(AdvancedInvokeCommandAction.CommandParameterProperty, value); } } /// <summary> /// Gets or sets the IValueConverter that is used to convert the EventArgs passed to the Command as a parameter. /// </summary> /// <remarks>If the <see cref="Command"/> or <see cref="EventArgsParameterPath"/> properties are set, this property is ignored.</remarks> public IValueConverter EventArgsConverter { get { return (IValueConverter)GetValue(EventArgsConverterProperty); } set { SetValue(EventArgsConverterProperty, value); } } /// <summary> /// Gets or sets the parameter that is passed to the EventArgsConverter. /// </summary> public object EventArgsConverterParameter { get { return (object)GetValue(EventArgsConverterParameterProperty); } set { SetValue(EventArgsConverterParameterProperty, value); } } /// <summary> /// Gets or sets the parameter path used to extract a value from an <see cref= "EventArgs" /> property to pass to the Command as a parameter. /// </summary> /// <remarks>If the <see cref="Command"/> propert is set, this property is ignored.</remarks> public string EventArgsParameterPath { get { return (string)GetValue(EventArgsParameterPathProperty); } set { SetValue(EventArgsParameterPathProperty, value); } } /// <summary> /// Specifies whether the EventArgs of the event that triggered this action should be passed to the Command as a parameter. /// </summary> /// <remarks>If the <see cref="Command"/>, <see cref="EventArgsParameterPath"/>, or <see cref="EventArgsConverter"/> properties are set, this property is ignored.</remarks> public bool PassEventArgsToCommand { get; set; } /// <summary> /// Invokes the action. /// </summary> /// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param> protected override void Invoke(object parameter) { if (this.AssociatedObject != null) { ICommand command = this.ResolveCommand(); if (command != null) { object eventArgs = null; object commandParameter = this.CommandParameter; //if no CommandParameter has been provided, let's check the EventArgsParameterPath if (!string.IsNullOrWhiteSpace(this.EventArgsParameterPath)) { eventArgs = GetEventArgsPropertyPathValue(parameter); } //next let's see if an event args converter has been supplied if (eventArgs == null && this.EventArgsConverter != null) { eventArgs = this.EventArgsConverter.Convert(parameter, typeof(object), EventArgsConverterParameter, CultureInfo.CurrentCulture); } //last resort, let see if they want to force the event args to be passed as a parameter if (eventArgs == null && this.PassEventArgsToCommand) { eventArgs = parameter; } if (command.CanExecute(commandParameter)) { var compositeCommandParameter = new CompositeCommandParameter((EventArgs)eventArgs, commandParameter); command.Execute(compositeCommandParameter); } } } } private object GetEventArgsPropertyPathValue(object parameter) { object commandParameter; object propertyValue = parameter; string[] propertyPathParts = EventArgsParameterPath.Split('.'); foreach (string propertyPathPart in propertyPathParts) { PropertyInfo propInfo = propertyValue.GetType().GetProperty(propertyPathPart); propertyValue = propInfo.GetValue(propertyValue, null); } commandParameter = propertyValue; return commandParameter; } private ICommand ResolveCommand() { ICommand command = null; if (this.Command != null) { command = this.Command; } else if (this.AssociatedObject != null) { // todo jekelly 06/09/08: we could potentially cache some or all of this information if needed, updating when AssociatedObject changes Type associatedObjectType = this.AssociatedObject.GetType(); PropertyInfo[] typeProperties = associatedObjectType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo propertyInfo in typeProperties) { if (typeof(ICommand).IsAssignableFrom(propertyInfo.PropertyType)) { if (string.Equals(propertyInfo.Name, this.CommandName, StringComparison.Ordinal)) { command = (ICommand)propertyInfo.GetValue(this.AssociatedObject, null); } } } } return command; } } }