简体   繁体   English

通过 InvokeCommandAction 使用多个参数时如何发送 EventArgs?

[英]How to send EventArgs when using multiple parameters through InvokeCommandAction?

I would like to use InvokeCommandAction to send MouseButtonEventArgs.ChangedButton and a parameter of my choice.我想使用InvokeCommandAction发送MouseButtonEventArgs.ChangedButton和我选择的参数。

I can send the arg value using TriggerParameterPath .我可以使用TriggerParameterPath发送 arg 值。

I can send multiple parameters using a MultiBinding along with a IMultiValueConverter .我可以使用MultiBindingIMultiValueConverter发送多个参数。

How can I do both?我怎样才能做到这两点?

Newer Prism versions use theMicrosoft.Xaml.Behaviors.Wpf package for the interactivity types, so the InvokeCommandAction type from there will be used in the following.较新的 Prism 版本将Microsoft.Xaml.Behaviors.Wpf package 用于交互类型,因此将使用以下类型的InvokeCommandAction For older versions using the legacy System.Windows.Interactivity types, the same is applicable.对于使用旧System.Windows.Interactivity类型的旧版本,同样适用。

If you inspect the code for the InvokeCommandAction type in the Invoke(object parameter) method , you can see that either the CommandParameter or the event arguments can be passed and if both are specified, the CommandParameter takes precedence.如果您在Invoke(object parameter)方法中检查InvokeCommandAction类型的代码,您可以看到可以传递CommandParameter或事件 arguments,如果两者都指定,则CommandParameter优先。 Consequently, by design this is not possible.因此,通过设计这是不可能的。

What you can do is create your own implementation of the InvokeCommanAction .您可以做的是创建自己的InvokeCommanAction实现。 Unfortunately, the type is marked sealed for some reason, so you are left to copy the implementation and adapt it.不幸的是,由于某种原因,该类型被标记为sealed ,因此您只能复制实现并对其进行调整。

The following serves as an example that you can vary to fit your requirements.以下作为示例,您可以根据自己的要求进行更改。 Create a type that can hold both the event arguments and the command parameter.创建一个可以同时保存事件 arguments 和命令参数的类型。

public class CompositeCommandParameter
{
   public CompositeCommandParameter(EventArgs eventArgs, object parameter)
   {
      EventArgs = eventArgs;
      Parameter = parameter;
   }

   public EventArgs EventArgs { get; }

   public object Parameter { get; }
}

Copy the original code of the InvokeCommandAction and adapt the Invoke method like this.复制InvokeCommandAction的原始代码并像这样调整Invoke方法。

protected override void Invoke(object parameter)
{
   if (AssociatedObject != null)
   {
      ICommand command = ResolveCommand();

      if (command != null)
      {
         object eventArgs = null;
         object commandParameter = CommandParameter;

         if (!string.IsNullOrWhiteSpace(EventArgsParameterPath))
         {
            eventArgs = GetEventArgsPropertyPathValue(parameter);
         }

         if (eventArgs == null && EventArgsConverter != null)
         {
            eventArgs = EventArgsConverter.Convert(parameter, typeof(object), EventArgsConverterParameter, CultureInfo.CurrentCulture);
         }

         if (eventArgs == null && PassEventArgsToCommand)
         {
            eventArgs = parameter;
         }

         if (command.CanExecute(commandParameter))
         {
            var compositeCommandParameter = new CompositeCommandParameter((EventArgs) eventArgs, commandParameter);
            command.Execute(compositeCommandParameter);
         }
      }
   }
}

The only difference to the original code is that now an instance of CompositeCommandParameter will be created with the event arguments and the CommandParameter that is passed to your bound command.与原始代码的唯一区别是,现在将使用事件 arguments 和传递给绑定命令的CommandParameter创建CompositeCommandParameter的实例。

Just for lazyness and easy setup, this would be the full command.只是为了懒惰和简单的设置,这将是完整的命令。 As a side note, the PassEventArgsToCommand may no longer be needed, as they should always be passed now.附带说明一下,可能不再需要PassEventArgsToCommand ,因为现在应该始终传递它们。

public sealed class CompositeInvokeCommandAction : TriggerAction<DependencyObject>
{
   private string commandName;

   public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CompositeInvokeCommandAction), null);
   public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(CompositeInvokeCommandAction), null);
   public static readonly DependencyProperty EventArgsConverterProperty = DependencyProperty.Register("EventArgsConverter", typeof(IValueConverter), typeof(CompositeInvokeCommandAction), new PropertyMetadata(null));
   public static readonly DependencyProperty EventArgsConverterParameterProperty = DependencyProperty.Register("EventArgsConverterParameter", typeof(object), typeof(CompositeInvokeCommandAction), new PropertyMetadata(null));
   public static readonly DependencyProperty EventArgsParameterPathProperty = DependencyProperty.Register("EventArgsParameterPath", typeof(string), typeof(CompositeInvokeCommandAction), 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
      {
         ReadPreamble();
         return commandName;
      }
      set
      {
         if (CommandName != value)
         {
            WritePreamble();
            commandName = value;
            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)GetValue(CommandProperty); }
      set { 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 GetValue(CommandParameterProperty); }
      set { SetValue(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 (AssociatedObject != null)
      {
         ICommand command = ResolveCommand();

         if (command != null)
         {
            object eventArgs = null;
            object commandParameter = CommandParameter;

            if (!string.IsNullOrWhiteSpace(EventArgsParameterPath))
            {
               eventArgs = GetEventArgsPropertyPathValue(parameter);
            }

            if (eventArgs == null && EventArgsConverter != null)
            {
               eventArgs = EventArgsConverter.Convert(parameter, typeof(object), EventArgsConverterParameter, CultureInfo.CurrentCulture);
            }

            if (eventArgs == null && 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 (Command != null)
      {
         command = Command;
      }
      else if (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 = 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, CommandName, StringComparison.Ordinal))
               {
                  command = (ICommand)propertyInfo.GetValue(AssociatedObject, null);
               }
            }
         }
      }

      return command;
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用MVVM在WPF应用程序中的InvokeCommandAction中将多个参数作为CommandParameter传递 - How to pass Multiple parameters as CommandParameter in InvokeCommandAction In WPF App Using MVVM 如何在Windows Phone的InvokeCommandAction中将多个参数作为CommandParameter传递 - How to pass Multiple parameters as CommandParameter in InvokeCommandAction in Windows phone 如何使用InvokeCommandAction调用我的方法并传入参数? - How do I go about using InvokeCommandAction to call a method of mine and pass in parameters? 使用EventArgs - Using the EventArgs 如何在连接事件时转换EventArgs? - How to Convert EventArgs when wiring events? 如何使用EventArgs获取事件详细信息? - How to get event details using EventArgs? 如何使用WebClient将多个参数发送到Web API调用 - How to send multiple parameters to a Web API call using WebClient 如何调用具有参数的方法(对象发送者,EventArgs e) - How to call method having parameters (object sender, EventArgs e ) 当无法访问EventArgs类型时,如何使用反射添加事件处理程序? - How to add an event handler using reflection when do not have access to EventArgs type? 对多个事件使用相同的EventArgs实例,此代码有味道吗? - Using the same EventArgs instance for multiple events, is this code smell?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM