Параметры команды

Последнее обновление: 29.01.2023

Команда может принимать параметры, через которые в команду можно передать некоторые данные извне. В частности, если мы посмотрим на определение метода 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 и нажатия на кнопку удаления выделенный объект будет удален:

Параметры комманд и свойство CommandParameter в реализации паттерна MVVM в приложении на Windows Forms и C#
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850