1

Introduction to the problem

I have a binding in XAML on a property in my view model, called "IsYoungerThanSeventy". Iøm using Prism to call a command on the event TargetUpdated. At the moment I'm passing Source (the BinaryQuestion) using TriggerParameterPath="Source".

The problem

I can't pass both Source and Property

What I want to do

I'd like to also pass the Property (IsYoungerThanSeventy) to the same command.

Ultimatly I need both the Source and Property in a function I'm calling to update stuff.

My code so far

<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>
Smedegaard
  • 727
  • 1
  • 6
  • 18
  • What is `Source` ? Isn't you already have it (it's VM where command is executed). I'd expect Quiz to have a collection of questions, then you probably have current question containing collection of answers of something like this. – Sinatr Feb 16 '17 at 12:20
  • Possible duplicate of [How to pass Multiple parameters as CommandParameter in InvokeCommandAction In WPF App Using MVVM](http://stackoverflow.com/questions/12601684/how-to-pass-multiple-parameters-as-commandparameter-in-invokecommandaction-in-wp) – R. Richards Feb 16 '17 at 12:29

2 Answers2

1

The Execute method of the ICommand interface accepts only a single parameter so for you to be able to pass two values you need to create a type that can hold these two values and then pass an instance of this type as the command parameter to the command.

The easiest way to do this would be to invoke the command from the code-behind of the view and create an instance of your custom type in here, e.g.:

<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);
    }
}

This doesn't break the MVVM pattern since you are just invoking the very same command from the very same view. MVVM is not about eliminating code from the view, it is about separation of concerns.

If you refuse to implement view-related behaviour in the code-behind for some strange reason you will have to wrap the functionality in a custom InvokeCommandAction class. You could add properties to this class that hold your source and property values and then invoked the command as I explained in the above sample code.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • Thanks, this is the most elegant solution I think. I actually got my question a bit wrong. I actually needed the `ResolvedSourcePropertyName` of the `BindingExpression` on the `AnswerRequired` property. So I implemented your solution with that. – Smedegaard Feb 17 '17 at 11:36
0

Have you tried passing no argument?

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

Then your command can be declared

PropertyBoundToAnswerRequiredChangedCommand = new DelegateCommand<DataTransferEventArgs>(OnPropertyBoundToAnswerRequiredChanged);

with

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

and you can use both.

Bertrand
  • 61
  • 2
  • 3