Отключение команды

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

Иногда необходимо, чтобы при некоторых условиях команда не срабатывала. Например, при наличии некорректных данных или в силу какаих-то иных причин. В этом случае можно отключать команду. Для этой цели в интерфейсе ICommand определен метод

bool CanExecute(object? arg);

Если он возвращает true, то команда будет доступна, если false, то не доступна.

Рассмотрим простейший пример. Пусть у нас есть следующая модель данных Person:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person(string name, int age)
    {
        Name = name; Age = age;
    }
}

Свойство Name здесь представляет имя, свойство Age - возраст человека. Однако теоретически этим свойствам могут быть переданы не совсем корректные данные. Например, свойству Age можно присвоить негативное или очень большое число, например, 11500. Аналогично свойству Name можно передать пустую строку или какое-нибудь нехорошее слово. И было бы неплохо, если пользователь вводит подобные некорректные значения, то они не могли бы использованы для свойств Person.

Допустим нам надо вывести на страницу список объектов Person и определить функционал по добавлению новых объектов Person в этот список. Для этого определим следущий класс MainViewModel:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace HelloApp;

public class MainViewModel : INotifyPropertyChanged
{
    string name = "";
    int age;
    public event PropertyChangedEventHandler? PropertyChanged;
    public ICommand AddCommand { get; set; }
    public ObservableCollection<Person> People { get; } = new();

    public MainViewModel()
    {
        // устанавливаем команду добавления
        AddCommand = new Command(() =>
        {
            People.Add(new Person(Name, Age));
            Name = "";
            Age = 0;
        },
        () => Age > 0 && Age < 110 && Name.Length > 2);
    }
    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 void OnPropertyChanged([CallerMemberName] string prop = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
        ((Command)AddCommand).ChangeCanExecute();
    }
}

Модель представления определяет свойство People, которое представляет коллекцию объектов, а также свойства Name и Age, через которые пользователь будет добавлять в список People новые данные.

Для добавления новых объектов Person в коллекцию People MainViewModel определяет команду AddCommand. Причем для создании команды применяется конструктор класса Command, который принимает два параметра:

AddCommand = new Command(() =>
{
    People.Add(new Person(Name, Age));
    Name = "";
    Age = 0;
},
() => Age > 0 && Age < 110 && Name.Length > 2);

Первый параметр - делегат Action собственно представляет команду, которая, используя свойства Name и Age, создает объект Person и добавляет его в коллекцию People.

Второй параметр - делегат Func<bool> определяет условие, при котором команда будет активна. Результат этого делегата представляет значение типа bool - если оно равно true, то команда активна. в данном случае возвращается true, если свойство Age больше 0 и меньше 110 и длина имени больше 2 символов. Во всех остальных случаях команда будет не активна.

То есть активность команды зависит от свойств Name и Age. Однако их значение может меняться по мере ввода символов, но активность команды автоматически не изменится. Для этого нам надо известить систему вручную. Для этой цели в классе Command опредлен метод ChangeCanExecute(), соответственно нам надо его вызвать. Поскольку при изменении свойств срабатывает метод OnPropertyChanged(), то именно в этом методе и вызываем метод ChangeCanExecute():

public void OnPropertyChanged([CallerMemberName] string prop = "")
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
    ((Command)AddCommand).ChangeCanExecute();
}

В файле MainPage.xaml.cs установим данную модель представления в качестве констекста привязки:

namespace HelloApp;

public partial class MainPage : ContentPage
{
    public MainPage()
	{
		InitializeComponent();
        BindingContext = new MainViewModel();
    }
}

В файле MainPage.xaml установим привязки свойств и команд модели представления к визуальным элементам:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloApp.MainPage">
    <VerticalStackLayout Padding="5">
        <VerticalStackLayout>
            <Entry Placeholder="Enter name" Text="{Binding Name}" />
            <Entry Placeholder="Enter age" Text="{Binding Age}"/>
            <Button Text="Save" WidthRequest="100" HorizontalOptions="Start"
                        Command="{Binding AddCommand}"  />
        </VerticalStackLayout>
        <ListView x:Name="peopleListView" ItemsSource="{Binding People}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <VerticalStackLayout>
                            <Label Text="{Binding Name}" />
                            <Label Text="{Binding Age}" />
                        </VerticalStackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </VerticalStackLayout>
</ContentPage>

Вначале страницы определено два текстовых поля, которые привязаны к свойствам Name и Age. А по нажатию кнопки Add срабатывает команда AddCommand. Таким образом, по нажатию на кнопку введенные в текстовые поля данные будут добавлены в список People в MainViewModel.

Чуть ниже определен элемент ListView, который выводит список People.

Однако если в текстовые поля будут введены некорреткные значения, то команда AddCommand будет недоступна, соответственно и кнопка будет недоступна:

Отключение команд в реализации паттерна MVVM в приложении на .NET MAUI и C#
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850