使用 InvokeCommandAction 传递 Source 和 属性,而不使用 MultiBindings

Passing both Source and Property with InvokeCommandAction, without using MultiBindings

问题介绍

我在视图模型中的 属性 上绑定了 XAML,称为 "IsYoungerThanSeventy"。我正在使用 Prism 对事件 TargetUpdated 调用命令。目前我正在使用 TriggerParameterPath="Source".

传递 SourceBinaryQuestion

问题

我不能同时通过 SourceProperty

我想做什么

我还想将 Property (IsYoungerThanSeventy) 传递给同一命令。

最终我需要在一个函数中同时使用 SourceProperty 来更新内容。

到目前为止我的代码

<wpfQuestionnaire:BinaryQuestion
    AnswerRequired="{Binding IsYoungerThanSeventy
        , Mode=TwoWay                                          
        , NotifyOnTargetUpdated=True}">

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="TargetUpdated">
            <prism:InvokeCommandAction 
                Command="{Binding PropertyBoundToAnswerRequiredChangedCommand}"
                TriggerParameterPath="Source"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</wpfQuestionnaire:BinaryQuestion>

ICommand 接口的 Execute 方法只接受一个参数,因此为了能够传递两个值,您需要创建一个可以保存这两个值的类型,然后传递此类型的实例作为命令的命令参数。

最简单的方法是从视图的 code-behind 调用命令并在此处创建自定义类型的实例,例如:

<wpfQuestionnaire:BinaryQuestion
    AnswerRequired="{Binding IsYoungerThanSeventy
        , Mode=TwoWay                                          
        , NotifyOnTargetUpdated=True}" TargetUpdated="BinaryQuestion_TargetUpdated">
</wpfQuestionnaire:BinaryQuestion>

private void BinaryQuestion_TargetUpdated(object sender, DataTransferEventArgs e)
{
    BinaryQuestion bq = sender as BinaryQuestion;
    ViewModel vm = bq.DataContext as ViewModel;
    if (vm != null)
    {
        YourCustomCompositeCommandArgumentType param = new YourCustomCompositeCommandArgumentType() { Source = bq, Parameter = vm.IsYoungerThanSeventy };
        vm.PropertyBoundToAnswerRequiredChangedCommand.Execute(param);
    }
}

这不会破坏 MVVM 模式,因为您只是从同一个视图调用同一个命令。 MVVM 不是要从视图中删除代码,而是要分离关注点。

如果您出于某种奇怪的原因拒绝在 code-behind 中实现 view-related 行为,您将不得不将功能包装在自定义 InvokeCommandAction class 中。您可以向此 class 添加属性以保存您的源和 属性 值,然后按照我在上面的示例代码中解释的那样调用命令。

你试过不传递参数吗?

<i:Interaction.Triggers>
    <i:EventTrigger EventName="TargetUpdated">
        <prism:InvokeCommandAction 
            Command="{Binding PropertyBoundToAnswerRequiredChangedCommand}"
            />
    </i:EventTrigger>
</i:Interaction.Triggers>

那么你的命令就可以声明了

PropertyBoundToAnswerRequiredChangedCommand = new DelegateCommand<DataTransferEventArgs>(OnPropertyBoundToAnswerRequiredChanged);

public void OnPropertyBoundToAnswerRequiredChanged(DataTransferEventArgs e){
var isYoungerThanSeventy = e.Property as bool;
var source = e.Source;
}

您可以同时使用两者。