Команда может принимать параметры, через которые в команду можно передать некоторые данные извне. В частности, если мы посмотрим на определение метода Execute
,
то увидим, что он принимает параметр, через который в команду передаются данные любого типа:
void Execute(object? parameter);
Для передачи данных в команду элементы графического интерфейса, которые поддерживают команды, например, класс Button
, имеют свойство CommandParameter. Это свойство
и представляет передаваемые в команду данные.
Рассмотрим применение параметров команды. Пусть у нас реализован следующий класс MainCommand:
public class MainCommand : ICommand { public event EventHandler? CanExecuteChanged; Action<object?> action; public MainCommand(Action<object?> action) { this.action = action; } public bool CanExecute(object? parameter) => true; public void Execute(object? parameter) => action?.Invoke(parameter); }
Метод Execute
принимает параметр parameter
- это то, что будет передаваться через свойство CommandParameter
визуальных компонентов.
Затем это значение передается в действие action.
Пусть данные представлены следующим классом Person:
public class Person { public int Id { get; set; } public string Name { get; set; } = ""; public int Age { get; set; } public override string ToString() => Name; }
Определим следующий класс модели представления MainViewModel:
using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Input; namespace HelloApp; public class MainViewModel : INotifyPropertyChanged { static int id = 0; // для генерации id // данные для нового объекта string name =""; int age; // команда для добавления public ICommand AddCommand { get; set; } // команда для удаления public ICommand RemoveCommand { get; set; } // данные для отображения в списке public BindingList<Person> People { get; } public string Name { get => name; set { if (name != value) { name = value; OnPropertyChanged(); } } } public int Age { get => age; set { if (age != value) { age = value; OnPropertyChanged(); } } } public MainViewModel() { People = new() { new Person {Id=++id, Name="Tom", Age=38 }, new Person {Id=++id, Name ="Bob", Age = 42}, new Person {Id=++id, Name = "Sam", Age = 25} }; // определяем команду добавления AddCommand = new MainCommand(_ => { People.Add(new Person { Id = ++id, Name = this.Name, Age = this.Age }); Name = ""; Age = 0; }); // определяем команду удаления RemoveCommand = new MainCommand(obj => { // ищем объект по id if(obj is int id) { var person = People.FirstOrDefault(p => p.Id == id); // если объект найден, удаляем его if (person != null) { People.Remove(person); } } }); } public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged([CallerMemberName] string prop = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop)); } }
Модель представления определяет свойство People, которое представляет коллекцию объектов, а также свойства Name и Age, через которые пользователь будет добавлять в список People новые данные.
MainViewModel определяет две команды. Команда AddCommand по свойствам Name и Age создает объект Person и добавляет его в коллекцию People.
Для удаления данных определена команда RemoveCommand
, которая получает параметр:
RemoveCommand = new MainCommand(obj => { if(obj is int id) { var person = People.FirstOrDefault(p => p.Id == id); if (person != null) { People.Remove(person); } } });
Для получения параметра в конструктор класса MainCommand передается делегат с одним параметров типа object?
. Такой параметр может представлять любой тип.
И в данном случае мы ожидаем, что будет передаваться идентификатор удаляемого объекта Person. Поэтому преобразуем параметр obj к типу int, находим соответствующий
объект Person и удаляем из коллекции People.
В коде установим данную модель представления в качестве констекста привязки:
namespace MetanitApp; public partial class Form1 : Form { public Form1() { InitializeComponent(); ListBox peopleListBox = new ListBox(); peopleListBox.Dock = DockStyle.Left; peopleListBox.SelectionMode = SelectionMode.One; Controls.Add(peopleListBox); Panel personForm = new Panel{ Padding = new Padding(10), Width=260 }; personForm.Dock = DockStyle.Right; TextBox nameBox = new TextBox(); nameBox.Location = new Point(12, 10); nameBox.Size = new Size(230, 27); personForm.Controls.Add(nameBox); NumericUpDown ageBox = new NumericUpDown { Minimum=0, Maximum=100 }; ageBox.Location = new Point(12, 50); ageBox.Size = new Size(230, 27); personForm.Controls.Add(ageBox); Button addButton = new Button { Text = "Save", AutoSize = true }; addButton.Location = new Point(12, 80); personForm.Controls.Add(addButton); Button removeButton = new Button { Text = "Remove", AutoSize = true }; removeButton.Location = new Point(12, 110); personForm.Controls.Add(removeButton); Controls.Add(personForm); // устанавливаем модель представления DataContext = new MainViewModel(); peopleListBox.DataBindings.Add(new Binding("DataSource", DataContext, "People")); peopleListBox.DisplayMember = "Name"; peopleListBox.ValueMember = "Id"; nameBox.DataBindings.Add(new Binding("Text", DataContext, "Name", true, DataSourceUpdateMode.OnPropertyChanged)); ageBox.DataBindings.Add(new Binding("Value", DataContext, "Age", true, DataSourceUpdateMode.OnPropertyChanged)); // привязка к команде добавления addButton.DataBindings.Add(new Binding("Command", DataContext, "AddCommand", true)); // привязка к команде удаления removeButton.DataBindings.Add(new Binding("Command", DataContext, "RemoveCommand", true)); // привязка к параметру команды removeButton.DataBindings.Add(new Binding("CommandParameter", peopleListBox, "SelectedValue")); } }
Вначале страницы определен компонент ListBox для вывода списка People. Далее на элементе Panel определены два поля ввода - TextBox и NumericUpDown о два текстовых поля, которые привязаны к свойствам Name и Age.
свойство Command
кнопки addButton привязано к команде AddButton. Таким образом, по нажатию на кнопку будет срабатывать команда AddCommand
, в которой введенные в текстовые поля данные будут добавлены в список People в MainViewModel.
Кроме того, определена кнопка удаления, которая привязана к команде RemoveCommand
и которая в качестве параметра команды передает выделенное значение в ListBox:
// привязка к команде удаления removeButton.DataBindings.Add(new Binding("Command", DataContext, "RemoveCommand", true)); // привязка к параметру команды выделенного значения в списке ListBox removeButton.DataBindings.Add(new Binding("CommandParameter", peopleListBox, "SelectedValue"));
Здесь стоит отметить, что выше для ListBox в качестве свойства значения задано свойство Id:
peopleListBox.ValueMember = "Id";
Поэтому свойство SelectedValue
в ListBox будет представлять Id выделенного элемента Person. А прявязка к параметру команды позволяет его передать в команду.
Таким образом, после выделения объекта в ListBox и нажатия на кнопку удаления выделенный объект будет удален: