我有一个命令,我使用以下标准语法从我的XAML文件执行:
<Button Content="Zoom" Command="{Binding MyViewModel.ZoomCommand}"/>
这很好用,直到我意识到我需要从视图中获取两条信息,以便按照用户期望的方式完成此操作(画布的宽度和高度)。
似乎可以将数组作为参数传递给我的命令,但是我没有看到在CommandParameter中指定绑定到我的两个canvas属性的方法:
<Button Content="Zoom"
Command="{Binding MyViewModel.ZoomCommand"
CommandParameter="{Binding ElementName=MyCanvas, Path=Width}"/>
如何将宽度和高度都传递给我的命令?使用XAML中的命令似乎不太可能,我需要在代码隐藏中连接一个单击处理程序,以便将此信息传递给我的缩放方法。
答案 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的区域。