TriggerAction扩展----ExInvokeCommandAction

本文介绍了一种改进的InvokeCommandAction方法,解决了无法获取发送者、无法使用EventArg参数及传递多个参数的问题。通过定义参数结构体和处理的TriggerAction,实现了更灵活的命令绑定功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  Wp&Win8中使用命令绑定时,除了Button控件自带命令绑定,其他的时候是用Interactivity库中的InvokeCommandAction实现的(Win8 需要额外安装第三方NuGet包才可使用,我的MVFM示例博客中带有这个库),但使用过程中发现InvokeCommandAction并不能满足我们的要求,主要有以下几点:
  1 无法获取发送者;
  2 用EventTrigger触发时往往需要用到EventArg参数,但是InvokeCommandAction无法获取;
  3 有时需要传递多个参数,无法满足;
  于是我对InvokeCommandAction进行了一些改进,首先定义参数的结构体:
    /// <summary>  
    /// 扩展CommandParameter,使CommandParameter可以带事件参数  
    /// </summary>  
    public class ExCommandParameter
    {
        /// <summary>  
        /// 事件触发源  
        /// </summary>  
        public object Sender { get; set; }
        /// <summary>  
        /// 事件参数  
        /// </summary>  
        public object EventArgs { get; set; }
        /// <summary>  
        /// 参数  
        /// </summary>  
        public object Parameter { get; set; }
        /// <summary>  
        /// 扩展参数  
        /// </summary>  
        public object Parameter2 { get; set; }
        /// <summary>  
        /// 扩展参数  
        /// </summary>  
        public object Parameter3 { get; set; }
    }  
  然后定义处理的TriggerAction:
 /// <summary>  
    /// 扩展的InvokeCommandAction  
    /// </summary>  
    public class ExInvokeCommandAction : CustomTriggerActionBase
    {
        private string commandName;
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(ExInvokeCommandAction), null);
        public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(ExInvokeCommandAction), null);
        public static readonly DependencyProperty CommandParameter2Property = DependencyProperty.Register("CommandParameter2", typeof(object), typeof(ExInvokeCommandAction), null);
        public static readonly DependencyProperty CommandParameter3Property = DependencyProperty.Register("CommandParameter3", typeof(object), typeof(ExInvokeCommandAction), null);

        /// <summary>  
        /// 获得或设置此操作应调用的命令的名称。  
        /// </summary>  
        /// <value>此操作应调用的命令的名称。</value>  
        /// <remarks>如果设置了此属性和 Command 属性,则此属性将被后者所取代。</remarks>  
        public string CommandName
        {
            get
            {
                return this.commandName;
            }
            set
            {
                if (this.commandName != value)
                {
                    this.commandName = value;
                }
            }
        }
   
        /// <summary>  
        /// 获取或设置此操作应调用的命令。这是依赖属性。  
        /// </summary>  
        /// <value>要执行的命令。</value>  
        /// <remarks>如果设置了此属性和 CommandName 属性,则此属性将优先于后者。</remarks>  
        public ICommand Command
        {
            get
            {
                return (ICommand)base.GetValue(ExInvokeCommandAction.CommandProperty);
            }
            set
            {
                base.SetValue(ExInvokeCommandAction.CommandProperty, value);
            }
        }
        /// <summary>  
        /// 获得或设置命令参数。这是依赖属性。  
        /// </summary>  
        /// <value>命令参数。</value>  
        /// <remarks>这是传递给 ICommand.CanExecute 和 ICommand.Execute 的值。</remarks>  
        public object CommandParameter
        {
            get
            {
                return base.GetValue(ExInvokeCommandAction.CommandParameterProperty);
            }
            set
            {
                base.SetValue(ExInvokeCommandAction.CommandParameterProperty, value);
            }
        }

        public object CommandParameter2
        {
            get
            {
                return base.GetValue(ExInvokeCommandAction.CommandParameter2Property);
            }
            set
            {
                base.SetValue(ExInvokeCommandAction.CommandParameter2Property, value);
            }
        }

        public object CommandParameter3
        {
            get
            {
                return base.GetValue(ExInvokeCommandAction.CommandParameter3Property);
            }
            set
            {
                base.SetValue(ExInvokeCommandAction.CommandParameter3Property, value);
            }
        }

        /// <summary>  
        /// 调用操作。  
        /// </summary>  
        /// <param name="parameter">操作的参数。如果操作不需要参数,则可以将参数设置为空引用。</param>  
        protected override void Invoke(object parameter)
        {
            ICommand command = this.ResolveCommand();

            ExCommandParameter exParameter = new ExCommandParameter
            {
                Sender = this.AssociatedObject,
                Parameter = GetValue(CommandParameterProperty),
                Parameter2 = GetValue(CommandParameter2Property),
                Parameter3 = GetValue(CommandParameter3Property),
                EventArgs = parameter

            };

            if (command != null && command.CanExecute(exParameter))
            {
                command.Execute(exParameter);
            }
        }

        //手动触发
        public void TriggerCommand()
        {
            Invoke(null);
        }

        public void TriggerCommand(object CommandParameter)
        {
            TriggerCommand(null, CommandParameter);
        }

        public void TriggerCommand(object sender = null, object commandParameter = null, object commandParameter2 = null, object commandParameter3 = null)
        {
            this.CommandParameter = commandParameter;
            this.CommandParameter2 = commandParameter2;
            this.CommandParameter3 = commandParameter3;
            Invoke(null);
        }

        protected ICommand ResolveCommand()
        {
            ICommand result = null;
            if (this.Command != null)
            {
                result = this.Command;
            }
            else
            {
                foreach (PropertyInfo propertyInfo in this.AssociatedObject.GetType().GetTypeInfo().DeclaredProperties)
                {
                    if (typeof(ICommand).GetTypeInfo().IsAssignableFrom(propertyInfo.PropertyType.GetTypeInfo()) && string.Equals(propertyInfo.Name, this.CommandName, StringComparison.Ordinal))
                    {
                        result = (ICommand)propertyInfo.GetValue((object)this.AssociatedObject, (object[])null);
                    }
                }
            }
            return result;
        }
    }
  使用时和InvokeCommandAction是一样的:
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">  
             <Behavior:ExInvokeCommandAction Command="{Binding Command,Source={StaticResource ViewModel}}" CommandParameter="1" CommandParameter2="2" CommandParameter3="3"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>

<think>嗯,用户遇到了一个报错信息:“TriggerAction 对象必须与一个并且只能与一个触发器对象关联。”我需要帮他理解这个问题。首先,我应该先分析这个错误可能出现在什么情况下。可能是在使用某种GUI框架,比如WPF或者类似的,因为TriggerAction和触发器对象通常在这些框架中出现。 用户可能是在尝试将同一个TriggerAction关联到多个触发器,或者可能没有正确地将动作绑定到触发器上。比如,在WPF中,每个Action必须只属于一个触发器,否则会引发异常。这时候需要检查代码,确保每个Action只被添加到一个触发器的Actions集合中。 接下来,我需要考虑用户的使用场景。可能是在开发桌面应用程序,使用XAML来定义界面交互。用户可能是在处理事件触发器,比如EventTrigger,并试图复用某个Action,导致重复关联。这时候需要提醒用户,每个Action实例只能使用一次,不能重复添加到不同的触发器。 另外,用户可能不太清楚如何正确关联Action和触发器,或者可能在动态生成界面元素时,错误地重复使用了同一个Action对象。这时候需要给出具体的示例,说明正确的代码结构,以及如何避免这种错误。 还需要考虑用户可能的代码错误点。例如,可能在XAML中多次引用了同一个Action资源,或者在代码后台多次将同一个Action实例添加到不同的触发器集合中。需要指出这些情况,并提供修改建议,比如每次创建新的Action实例,而不是复用。 此外,可能需要解释TriggerActionTrigger的关系,说明每个Action必须只能属于一个Trigger,这是框架的设计约束,防止状态混乱或不可预测的行为。用户可能没有意识到这一点,所以需要明确说明背后的原理。 最后,要确保回答清晰易懂,分点说明错误原因和解决方法,并给出示例代码帮助用户理解。同时,使用用户可能熟悉的术语,比如XAML、事件触发器、代码后台等,帮助他们更好地定位问题所在。</think>这个报错通常出现在使用事件触发器(如 WPF、Unity 等框架)时,表示你试图将一个 `TriggerAction`(触发器动作)同时关联到多个触发器对象,或者没有正确绑定到任何一个触发器。 --- ### **错误原因** 1. **重复关联**:同一个 `TriggerAction` 实例被多次添加到不同触发器(`Trigger`)的 `Actions` 集合中。 2. **未关联触发器**:`TriggerAction` 没有被正确绑定到任何一个触发器(即“游离”状态)。 3. **框架限制**:许多框架要求 `TriggerAction` 必须严格与**唯一一个触发器**绑定,否则会引发冲突。 --- ### **解决方案** #### 1. **确保一对一绑定** - 每个 `TriggerAction` 实例只能被添加到一个触发器的 `Actions` 集合中。 - ❌ 错误示例(C# WPF): ```csharp var action = new MyTriggerAction(); trigger1.Actions.Add(action); trigger2.Actions.Add(action); // 同一 action 被重复关联! ``` - ✅ 正确修改: ```csharp var action1 = new MyTriggerAction(); var action2 = new MyTriggerAction(); trigger1.Actions.Add(action1); trigger2.Actions.Add(action2); ``` #### 2. 检查 XAML 代码(如适用) - 在 XAML 中,确保没有通过 `StaticResource` 复用同一个 `TriggerAction`: ```xml ❌ 错误: <Window.Resources> <local:MyTriggerAction x:Key="SharedAction"/> </Window.Resources> <Button> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <StaticResource ResourceKey="SharedAction"/> </i:EventTrigger> <i:EventTrigger EventName="MouseEnter"> <StaticResource ResourceKey="SharedAction"/> <!-- 重复使用! --> </i:EventTrigger> </i:Interaction.Triggers> </Button> ``` #### 3. 确认触发器正确初始化 - 在代码中动态创建触发器时,确保 `TriggerAction` 被正确关联: ```csharp var trigger = new EventTrigger(); var action = new MyTriggerAction(); trigger.Actions.Add(action); // 正确关联 ``` --- ### **底层逻辑** 框架要求 `TriggerAction` 与触发器严格一一对应,是为了避免以下问题: - **状态冲突**:同一动作可能在多个触发器中共享内部状态,导致不可预知的行为。 - **生命周期管理**:触发器需要控制其关联动作的初始化和销毁。 如果遇到此问题,仔细检查代码中所有操作 `TriggerAction` 的地方,确保每个实例仅被使用一次。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值