Search code examples
wpfmvvmcommandmultibindingrelaycommand

WPF MVVM Multibinding - How to pass two parameters to Command using RelayCommand


How to pass 2 parameters to command using RelayCommand. I need to pass COntrols as parameters (Grid and Window). I'm fully aware that such kind of problem has already existed on Stack Overflow but I'm struggling with adjusting that to my needs.

  1. See look my first attempt is following. It obviously doesn't work because the Relay can't get 2 arguments.

Xaml code:

        <Button Name="StretchScreenBtn" Content="Stretch screen" DataContext="   {StaticResource CommandWindow}" Command="{Binding ResizeScreenCommand}"
                Width="100" Height="50">
             <Button.CommandParameter>
                <MultiBinding Converter="{StaticResource CommandParamsConv}">
                    <Binding ElementName="ScreenGrid" />
                    <Binding RelativeSource="{RelativeSource AncestorType=Window}" /> 
                </MultiBinding> 
            </Button.CommandParameter>  
        </Button>

The Command code from ViewModel:

        private ICommand _ResizeScreenCommand;
        public ICommand ResizeScreenCommand
        {
            get
            {
                if (_ResizeScreenCommand == null)
                {
                    _ResizeScreenCommand = new RelayCommand(
                        (argument1, argument2) =>
                        {

                            Grid grid = argument1 as Grid;
                            Window window = argument2 as Window;
                            if ((int)grid.GetValue(Grid.ColumnSpanProperty) == 2)
                            {
                                grid.SetValue(Grid.ColumnSpanProperty, 1);
                                window.WindowStyle = WindowStyle.None;
                            }
                            else
                            {
                                grid.SetValue(Grid.ColumnSpanProperty, 2);
                                window.WindowStyle = WindowStyle.SingleBorderWindow;
                            }
                        }
                        );
                }
                return _ResizeScreenCommand;
            }
        }

And the MultiValueConverter:

     class CommandParamsConverter : IMultiValueConverter
     {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            object[] parameters = values;
            return parameters;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
     }
  1. My second attempt I followed the solution from How to Passing multiple parameters RelayCommand?

So, I've created within the ViewModel the new class, with two properties Grid and Window types and then tried to bind in xaml the Elements to these properties. But i this case the compiler complains that these properties are non-dependancy and cannot be bindded.

Please give me any hint how to solve it?

Below is the modified xaml code:

        <Button Name="StretchScreenBtn" Content="Stretch screen" DataContext="{StaticResource CommandWindow}" Command="{Binding ResizeScreenCommand}"
                Width="100" Height="50">
             <Button.CommandParameter>
                <vm:StretchingModel Grid="{Binding ElementName=ScreenGrid}" Win="{Binding RelativeSource={RelativeSource AncestorType=Window}}" />
            </Button.CommandParameter>  
        </Button>

And the additionall class in the ViewModel:

    class StretchingModel
    {
        public Grid Grid { get; set; }
        public Window Win { get; set; }
    } 

Solution

  • Passing a Grid and a Window to a view model is not MVVM...a view model shouldn't have any dependencies upon any UI elements.

    Anyway, to pass more than one value to the command you should combine your two approaches. The converter should return an instance of a StretchingModel:

    class CommandParamsConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return new StretchingModel() { Grid = values[0], Window = values[1] };
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    ...that the command accepts:

    private ICommand _ResizeScreenCommand;
    public ICommand ResizeScreenCommand
    {
        get
        {
            if (_ResizeScreenCommand == null)
            {
                _ResizeScreenCommand = new RelayCommand(
                    (argument) =>
                    {
    
                        StretchingModel model = argument as StretchingModel;
                        ...
                    }
                    );
            }
            return _ResizeScreenCommand;
        }
    }