Передача двух параметров команды с использованием привязки WPF
У меня есть команда, которую я выполняю из моего файла XAML, используя следующий стандартный синтаксис:
<Button Content="Zoom" Command="{Binding MyViewModel.ZoomCommand}"/>
Это работало нормально, пока я не понял, что мне нужно ДВА фрагмента информации из представления, чтобы эта операция завершилась так, как ожидают пользователи (в частности, ширина и высота холста).
Кажется, что возможно передать массив в качестве аргумента моей команде, но я не вижу способа указать привязку к двум моим свойствам холста в CommandParameter:
<Button Content="Zoom"
Command="{Binding MyViewModel.ZoomCommand"
CommandParameter="{Binding ElementName=MyCanvas, Path=Width}"/>
Как передать ширину и высоту моей команде? Похоже, что это невозможно при использовании команд из XAML, и мне нужно подключить обработчик щелчков в моем коде, чтобы эта информация передавалась моему методу масштабирования.
Ответы
Ответ 1
Во-первых, если вы делаете MVVM, вы, как правило, предоставляете эту информацию своей виртуальной машине через отдельные свойства, связанные с представлением. Это избавляет вас от необходимости передавать любые параметры вашим командам.
Однако вы также можете многосвязывать и использовать конвертер для создания параметров:
<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];
}
Ответ 2
В конвертере выбранного решения вы должны добавить values.Clone() в противном случае параметры в конце команды null
public class YourConverter : IMultiValueConverter
{
public object Convert(object[] values, ...)
{
return values.Clone();
}
...
}
Ответ 3
Используйте Tuple in Converter, а в 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;
}
Ответ 4
Что касается использования Tuple в Converter, было бы лучше использовать "объект" вместо "строка", чтобы он работал для всех типов объектов без ограничения объекта "строка".
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;
}
и multi-bind с конвертером для создания параметров (с двумя объектами 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
Если ваши значения статичны, вы можете использовать x:Array
:
<Button Command="{Binding MyCommand}">10
<Button.CommandParameter>
<x:Array Type="system:Object">
<system:String>Y</system:String>
<system:Double>10</system:Double>
</x:Array>
</Button.CommandParameter>
</Button>