使用WPF绑定传递两个命令参数

时间:2009-08-29 05:58:45

标签: wpf binding path command

我有一个命令,我使用以下标准语法从我的XAML文件执行:

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

这很好用,直到我意识到我需要从视图中获取两条信息,以便按照用户期望的方式完成此操作(画布的宽度和高度)。

似乎可以将数组作为参数传递给我的命令,但是我没有看到在CommandParameter中指定绑定到我的两个canvas属性的方法:

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

如何将宽度和高度都传递给我的命令?使用XAML中的命令似乎不太可能,我需要在代码隐藏中连接一个单击处理程序,以便将此信息传递给我的缩放方法。

6 个答案:

答案 0 :(得分:214)

首先,如果您正在使用MVVM,通常可以通过绑定视图的单独属性向VM提供此信息。这样可以节省您必须将任何参数传递给您的命令。

但是,您也可以多重绑定并使用转换器来创建参数:

<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>

在您的转换器中:

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

    ...
}

然后,在命令执行逻辑中:

public void OnExecute(object parameter)
{
    var values = (object[])parameter;
    var width = (double)values[0];
    var height = (double)values[1];
}

答案 1 :(得分:37)

在所选解决方案的转换器中,您应该添加values.Clone()否则命令中的参数为null

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

    ...
}

答案 2 :(得分:13)

在Converter中使用Tuple,在OnExecute中,将参数对象强制转换回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;
}

答案 3 :(得分:2)

如果您的值是静态的,则可以使用users

screenings

答案 4 :(得分:1)

关于在Converter中使用Tuple,最好使用'object'而不是'string',这样它可以适用于所有类型的对象而不受'string'对象的限制。

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

然后Command中的执行逻辑可能是这样

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

并与转换器多绑定以创建参数(带有两个TextBox对象)

<Button Content="Zip/City paste" Command="{Binding PasteClick}" >
    <Button.CommandParameter>
        <MultiBinding Converter="{StaticResource YourConvert}">
            <Binding ElementName="txtZip"/>
            <Binding ElementName="txtCity"/>
        </MultiBinding>
    </Button.CommandParameter>
</Button>

答案 5 :(得分:0)

这个任务也可以用不同的方法来解决。您还可以在 ViewModel 中聚合各种参数,而不是在 XAML 中编写转换器和放大代码。因此,ViewModel 又多了一个包含所有参数的属性。

我当前应用程序的一个例子,它也让我处理这个话题。 需要通用的 RelayCommand:https://stackoverflow.com/a/22286816/7678085

ViewModelBase 在这里通过命令 SaveAndClose 进行了扩展。泛型类型是一个命名元组,表示各种参数。

public ICommand SaveAndCloseCommand => saveAndCloseCommand ??= new RelayCommand<(IBaseModel Item, Window Window)>
    (execute =>
    {
        execute.Item.Save();
        execute.Window?.Close(); // if NULL it isn't closed.
    },
    canExecute =>
    {
        return canExecute.Item?.IsItemValide ?? false;
    });
private ICommand saveAndCloseCommand;

然后根据泛型类型包含一个属性:

public (IBaseModel Item, Window Window) SaveAndCloseParameter 
{ 
    get => saveAndCloseParameter ; 
    set 
    {
        SetProperty(ref saveAndCloseParameter, value);
    }
}
private (IBaseModel Item, Window Window) saveAndCloseParameter;

视图的 XAML 代码如下所示: (注意经典点击事件)

<Button 
    Command="{Binding SaveAndCloseCommand}" 
    CommandParameter="{Binding SaveAndCloseParameter}" 
    Click="ButtonApply_Click" 
    Content="Apply"
    Height="25" Width="100" />
<Button 
    Command="{Binding SaveAndCloseCommand}" 
    CommandParameter="{Binding SaveAndCloseParameter}" 
    Click="ButtonSave_Click" 
    Content="Save"
    Height="25" Width="100" />

在视图后面的代码中,然后评估点击事件,然后设置参数属性。

private void ButtonApply_Click(object sender, RoutedEventArgs e)
{
    computerViewModel.SaveAndCloseParameter = (computerViewModel.Computer, null);
}

private void ButtonSave_Click(object sender, RoutedEventArgs e)
{
    computerViewModel.SaveAndCloseParameter = (computerViewModel.Computer, this);
}

就我个人而言,我认为使用点击事件并没有打破 MVVM 模式。程序流控还是位于ViewModel的区域。