1

So, I have an element which has a command with 2 parameters to pass.

I previously did this with a snippet of code I found, but cannot for the life of me remember how to do it or find it again.

So, here is the multivalueconverter I previously created:

public class MultiValueConverter : IMultiValueConverter
{

    public object Convert(object[] values, Type targetType,
    object parameter, CultureInfo culture)
    {
        return values.Clone();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return (value as string).Split(' ');
    }

}

Now, I need to just assign the function I want to call in the ICommand. I normally use a line similar to:

enemyPopupTooltip = new RelayCommand(param => this.EnemyPopupTooltipEx(param),null);

However, this wont work when its multivalue.How can I use my relaycommand to pass 2 parameters, using the multivalueconverter, into my function?

For reference, here is everything inside relaycommand class:

public class RelayCommand : ICommand
{
    /// <summary>
    /// Initializes a new instance of the <see cref="RelayCommand"/> class.
    /// </summary>
    /// <param name="execute">The execute.</param>
    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="RelayCommand"/> class.
    /// </summary>
    /// <param name="execute">The execute.</param>
    /// <param name="canExecute">The can execute.</param>
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute;
        _canExecute = canExecute;
    }

    /// <summary>
    /// Defines the method that determines whether the command can execute in its current state.
    /// </summary>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    /// <returns>
    /// true if this command can be executed; otherwise, false.
    /// </returns>
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    /// <summary>
    /// Occurs when changes occur that affect whether or not the command should execute.
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    /// <summary>
    /// Defines the method to be called when the command is invoked.
    /// </summary>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    /// <summary>
    /// Action
    /// </summary>
    private readonly Action<object> _execute;


    /// <summary>
    /// Predicate
    /// </summary>
    private readonly Predicate<object> _canExecute;
pingu2k4
  • 956
  • 2
  • 15
  • 31
  • http://stackoverflow.com/questions/1350598/passing-two-command-parameters-using-a-wpf-binding – MajkeloDev Jul 03 '15 at 07:47
  • That linked question doesnt show what wouldbe written inside MyViewModel.ZoomCommand, which is what im struggling with :( – pingu2k4 Jul 03 '15 at 07:49
  • Second apporach: Can't You bind required parameters to some ViewModel property ? Then You will just call VM properties in Your method – MajkeloDev Jul 03 '15 at 07:51

3 Answers3

2

you said:

However, this wont work when its multivalue

This assumption is wrong. It does work!

When your multiconverter returns array of values, then this array is passed as a parameter to Command.Execute method.

new RelayCommand(EnemyPopupTooltipEx, null);

public void EnemyPopupTooltipEx(object parameter){
   var values = (object[])parameters;
}

however, this is very dirty approach. I guess you are passing some UIElement(s) to the command parameter. This is violation of viewmodel's responsibility. Consider moving code that need reference to UIElement to codebehind.

Liero
  • 25,216
  • 29
  • 151
  • 297
  • i know this is dirty approach, but some situation we have to do. For eg. If i want to refresh my datagrid then we need to send the UIElement element. – Joby James Jul 03 '15 at 10:39
  • you never need to send UI element to viewmodel, believe me. It's offtopic, but if you are interested how to do clean way, create new question and notify me by adding comment here. – Liero Jul 03 '15 at 10:44
  • Added a new qestion (How to refresh my DataGrid using MVVM) – Joby James Jul 03 '15 at 11:44
0

Just put your two parameters into one object. You could use any kind of collection or array, but perhaps the simplest option is to use the Tuple<T1, T2> Class in your IMultiValueConverter:

if (values != null && values.Length >= 2)
{
    Tuple<Type1, Type2> yourTwoValues = new Tuple<Type1, Type2>(values[0], values[1]);
    return yourTwoValues;
}

Then you can pass the Tuple to your ICommand as the parameter and extract the individual values at the other end.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • OK, thanks. Would my relaycommand look idnetical to above in that case? – pingu2k4 Jul 03 '15 at 08:06
  • Yes. The `RelayCommand.Execute` method has an `object parameter` and a `Tuple` is an `object` so you could pass that as the parameter. – Sheridan Jul 03 '15 at 09:23
0

Try with new Property, Do multibing in CommandParameter and Handle in ExecuteEnterCommand. like object[] arr = (object[])obj;

 public ICommand EnemyPopupTooltip
        {
            get
            {
                if (this.enemyPopupTooltip == null)
                {
                    this.enemyPopupTooltip = new RelayCommand<object>(this.ExecuteEnterCommand, this.CanExecuteEnterCommand);
                }

                return this.enemyPopupTooltip;
            }
        }


        private ICommand enemyPopupTooltip;
Joby James
  • 429
  • 8
  • 22