Passing two command parameters using a WPF binding

2019-01-04 05:14发布

I have a command which I am executing from my XAML file using the following standard syntax:

<Button Content="Zoom" Command="{Binding MyViewModel.ZoomCommand}"/>

This worked fine until I realized that I needed TWO pieces of information from the view in order to make this operation complete the way users expect (the width and height of the canvas specfically).

It seems like it's possible to pass an array as an argument to my command, but I don't see there being a way to specify the binding to my two canvas properties in the CommandParameter:

<Button Content="Zoom" 
        Command="{Binding MyViewModel.ZoomCommand" 
        CommandParameter={Binding ElementName=MyCanvas, Path=Width}"/>

How do I pass both Width and Height to my command? It doesn't seem like this is possible using commands from XAML and I need to wire up a click handler in my codebehind to get this information to pass to my zoom method.

4条回答
家丑人穷心不美
2楼-- · 2019-01-04 05:47

About using Tuple in Converter, it would be better to use 'object' instead of 'string', so that it works for all types of objects without limitation of 'string' object.

public class YourConverter : IMultiValueConverter 
{      
    public object Convert(object[] values, ...)     
    {   
        Tuple<object, object> tuple = new Tuple<object, object>(values[0], values[1]);
        return tuple;
    }      
} 

Then execution logic in Command could be like this

public void OnExecute(object parameter) 
{
    var param = (Tuple<object, object>) parameter;

    // e.g. for two TextBox object
    var txtZip = (System.Windows.Controls.TextBox)param.Item1;
    var txtCity = (System.Windows.Controls.TextBox)param.Item2;
}

and multi-bind with converter to create the parameters (with two TextBox objects)

<Button Content="Zip/City paste" Command="{Binding PasteClick}" >
    <Button.CommandParameter>
        <MultiBinding Converter="{StaticResource YourConvert}">
            <Binding ElementName="txtZip"/>
            <Binding ElementName="txtCity"/>
        </MultiBinding>
    </Button.CommandParameter>
</Button>
查看更多
狗以群分
3楼-- · 2019-01-04 06:02

In the converter of the chosen solution, you should add values.Clone() otherwise the parameters in the command end null

public class YourConverter : IMultiValueConverter
{
    public object Convert(object[] values, ...)
    {
        return values.Clone();
    }

    ...
}
查看更多
Luminary・发光体
4楼-- · 2019-01-04 06:02

Use Tuple in Converter, and in OnExecute, cast the parameter object back to Tuple.

public class YourConverter : IMultiValueConverter 
{      
    public object Convert(object[] values, ...)     
    {   
        Tuple<string, string> tuple = new Tuple<string, string>(
            (string)values[0], (string)values[1]);
        return (object)tuple;
    }      
} 

// ...

public void OnExecute(object parameter) 
{
    var param = (Tuple<string, string>) parameter;
}
查看更多
Summer. ? 凉城
5楼-- · 2019-01-04 06:08

Firstly, if you're doing MVVM you would typically have this information available to your VM via separate properties bound from the view. That saves you having to pass any parameters at all to your commands.

However, you could also multi-bind and use a converter to create the parameters:

<Button Content="Zoom" Command="{Binding MyViewModel.ZoomCommand">
    <Button.CommandParameter>
        <MultiBinding Converter="{StaticResource YourConverter}">
             <Binding Path="Width" ElementName="MyCanvas"/>
             <Binding Path="Height" ElementName="MyCanvas"/>
        </MultiBinding>
    </Button.CommandParameter>
</Button>

In your converter:

public class YourConverter : IMultiValueConverter
{
    public object Convert(object[] values, ...)
    {
        return values.Clone();
    }

    ...
}

Then, in your command execution logic:

public void OnExecute(object parameter)
{
    var values = (object[])parameter;
    var width = (double)values[0];
    var height = (double)values[1];
}
查看更多
登录 后发表回答