[英]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
.我可以使用
MultiBinding
和IMultiValueConverter
发送多个参数。
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.