2

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; }
    } 
M_K
  • 109
  • 1
  • 15
  • So you want to bind controls to command (which is frowned upon and highly not recommended) and you already know the answer to the title of your question. I'll just say use MVVM and don't bind Controls to anything. – Bizhan Jul 17 '18 at 17:31
  • Yes I know, but I don't use the controls by their names in code-behind. I mean they are passed from the View to ViewModel and the VieModel sees them as an object type and then converts them to proper types (Grid and Window). Anyway Bijan, could you propose your idea how would you do this binding? – M_K Jul 17 '18 at 17:57
  • the idea is standard MVVM, where VM does not know about View. whatever View you need to use binding on, surely has a VM which should be used instead. And to visualize the VM whichever style or template was used to render the View in the first place can be used to render the bound VM. – Bizhan Jul 17 '18 at 18:09
  • Ok, I'll try to do that. But what in case of Dialog Windows in MVVM? I would need to use OpenFileDialog so I would create the appropriate classes in the View and then use created class of OpenFileDialog from View in XAML to set the values of properties (like Caption, Filter etc) and bind it to to any button Command which would run the window. And then I would also need to pass the FilePath from the View to the Command in ViewModel which would handle the file opening and how to do these things? Have you ever handled the Dialog Windows in Xaml. Could you give me any hints? – M_K Jul 17 '18 at 18:36
  • this post can help with `OpenFileDialog` https://stackoverflow.com/q/1619505/366064 – Bizhan Jul 17 '18 at 18:40
  • Ok thanks, I'll try it also. In case I'm not able to solve it I'll reactivate the issue – M_K Jul 17 '18 at 18:49
  • Passing a Control and a Window to a viewmodel isn't mvvm, so your solution is to just do what you intend on doing in the codebehind. This smells like you've moved UI logic into a view model. That's not MVVM. View logic belongs in the view, inside the codebehind. –  Jul 17 '18 at 18:56

1 Answers1

0

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;
    }
}
mm8
  • 163,881
  • 10
  • 57
  • 88