WPF-MVVM-InvokeCommandAction传递多个参数

1 篇文章 0 订阅

InvokeCommandAction传递多个参数

命名空间:

xmlns:i=“http://schemas.microsoft.com/xaml/behaviors”

一般写法,一般只能传递一个参数

<i:Interaction.Triggers>
    <i:EventTrigger EventName="LostFocus">
        <i:InvokeCommandAction Command="{Binding DataContext.LostFocusCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" PassEventArgsToCommand="True" />
    </i:EventTrigger>
    <i:EventTrigger EventName="GotFocus">
        <i:InvokeCommandAction Command="{Binding DataContext.GotFocusCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" PassEventArgsToCommand="True" />
    </i:EventTrigger>
    <!--CommandParameter="itemGrid",这种后台参数为itemGrid-->
    <i:EventTrigger EventName="MouseEnter">
        <i:InvokeCommandAction  Command="{Binding DataContext.MouseEnterCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
                               CommandParameter="itemGrid"
                               PassEventArgsToCommand="True" />
    </i:EventTrigger>
</i:Interaction.Triggers>
解析Command
Command="{Binding DataContext.LostFocusCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" 

Binding DataContext.LostFocusCommand——》DataContext,View对应的ViewModel (这里用的是Prism框架)

传递的是 ViewModel 的 DelegateCommand

Command="{Binding DataContext.LostFocusCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" 
Binding RelativeSource

RelativeSource={RelativeSource AncestorType={x:Type UserControl}} 指向 源对象

RelativeSource首先要3个关键参数

AncestorType=需要查找的类型。比如Grid

AncestorLevel= 需要向上查找几级。

Path=我们找到的元素需要绑定的属性。

<!--嵌套Grid-->
    <Grid x:Name="G0" Margin="12" Background="Red">
        <TextBlock Text="In this Grid0 container"/>
        <Grid x:Name="G1" Margin="12" Background="Blue">
            <TextBlock Text="In this Grid1 container"/>
            <Grid x:Name="G2" Margin="12" Background="Yellow">
                <TextBlock Text="In this Grid2 container"/>
                <Grid x:Name="G3" Margin="12" Background="Beige">
                    <StackPanel>
                        <TextBlock Text="In this Grid3 container"/>
                        <!--AncestorType=我们需要查找的类型。比如Grid-->
                        <!--AncestorLevel= 我们需要向上查找几级-->
                        <!--Path=我们找到的元素需要绑定的属性。-->
                        <TextBlock Name="ces" Text="{Binding RelativeSource={RelativeSource AncestorType=Grid,AncestorLevel=1},Path=Name}"/>
                    </StackPanel>
                </Grid>
            </Grid>
        </Grid>
    </Grid>

我们嵌套几个Grid,并在每个嵌套的Grid中都放入了一行文本用来显示自己所在的位置。

设置了Margin使他有部分的重叠,可以更好的看到相互之间的层级关系。

最内层使用一个TextBlock.在TextBlock的Text属性上使用RelativeSource。

通过修改AncestorLevel 来设置向上查找Grid的等级。

我们设置为1.向外层查找第一个找到的Grid对象。并绑定对应的Name。

参考网址

传递两个或多个参数

方式一
定义一个转换器
namespace 命名空间
{
    /// <summary>
    /// CommandParameter 多参数传递
    /// </summary>
    public class ObjectConvert : IMultiValueConverter
    {
        #region IMultiValueConverter Members

        public static object ConverterObject;

        public object Convert(object[] values, Type targetType,
          object parameter, System.Globalization.CultureInfo culture)
        {
            ConverterObject = values;
            string str = values.GetType().ToString();
            return values.ToArray();
        }

        public object[] ConvertBack(object value, Type[] targetTypes,
          object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion IMultiValueConverter Members
    }
}

缺点,无法传递 EventArgs

<i:EventTrigger EventName="MouseEnter">
    <i:InvokeCommandAction Command="{Binding DataContext.MouseEnterCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" PassEventArgsToCommand="True">
        <i:InvokeCommandAction.CommandParameter>
            <MultiBinding Converter="{StaticResource ResourceKey=ObjectConvert}" Mode="TwoWay">
                <MultiBinding.Bindings>
                    <Binding ElementName="Grid" />
                    <Binding ElementName="TxtTitleInput" />
                </MultiBinding.Bindings>
            </MultiBinding>
        </i:InvokeCommandAction.CommandParameter>
    </i:InvokeCommandAction>
</i:EventTrigger>
方式二
传递两个
<i:EventTrigger EventName="MouseDown">
    <helper:AdvancedInvokeCommandAction
                                        Command="{Binding DataContext.MouseClickCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
                                        CommandParameter="{Binding ElementName=itemGrid}"
                                        PassEventArgsToCommand="True" />
</i:EventTrigger>
重写Invoke
namespace 命名空间
{
    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;
        }
    }
}

参考网址

传递多个参数
定义一个转换器
namespace 命名空间
{
    /// <summary>
    /// CommandParameter 多参数传递
    /// </summary>
    public class ObjectConvert : IMultiValueConverter
    {
        #region IMultiValueConverter Members

        public static object ConverterObject;

        public object Convert(object[] values, Type targetType,
          object parameter, System.Globalization.CultureInfo culture)
        {
            ConverterObject = values;
            string str = values.GetType().ToString();
            return values.ToArray();
        }

        public object[] ConvertBack(object value, Type[] targetTypes,
          object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion IMultiValueConverter Members
    }
}

结合传递两个参数的方法

<i:EventTrigger EventName="MouseEnter">
    <helper:AdvancedInvokeCommandAction Command="{Binding DataContext.MouseEnterCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" PassEventArgsToCommand="True">
        <helper:AdvancedInvokeCommandAction.CommandParameter>
            <MultiBinding Converter="{StaticResource ResourceKey=ObjectConvert}" Mode="TwoWay">
                <MultiBinding.Bindings>
                    <Binding ElementName="itemGrid" />
                    <Binding ElementName="TextBlockTitle" />
                </MultiBinding.Bindings>
            </MultiBinding>
        </helper:AdvancedInvokeCommandAction.CommandParameter>
    </helper:AdvancedInvokeCommandAction>
    <!--<i:InvokeCommandAction Command="{Binding DataContext.MouseEnterCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" PassEventArgsToCommand="True" />-->
</i:EventTrigger>

参考网址

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值