Язык программирования C#9 и платформа .NET5
В результате появляется возможность добавления автомобилей и обновления их цветов (пока с весьма ограниченной функциональностью) с помощью многократно используемого кода, содержащегося в автономных классах.
Изменение класса ChangeColorCommand
Финальным шагом будет обновление класса
, чтобы он стал унаследованным отChangeColorCommand. Замените интерфейсCommandBaseклассомICommand, добавьте к обоим методам ключевое словоCommandBaseи удалите код событияoverride. Все оказалось действительно настолько просто! Вот как выглядит новый код:CanExecuteChangedpublic class ChangeColorCommand : CommandBase{public override bool CanExecute(object parameter)=> parameter is Car;public override void Execute(object parameter){((Car)parameter).Color = "Pink";}}Объекты RelayCommand
Еще одной реализацией паттерна "Команда" (Command) в WPF является
. Вместо создания нового класса, представляющего каждую команду, данный паттерн применяет делегаты для реализации интерфейсаRelayCommand. Реализация легковесна в том, что каждая команда не имеет собственного класса. ОбъектыICommandобычно используются, когда нет необходимости в многократном применении реализации команды.RelayCommandСоздание базового класса RelayCommand
Как правило, объекты
реализуются в двух классах. Базовый классRelayCommandиспользуется при отсутствии каких-либо параметров для методовRelayCommandиCanExecute(), а классExecute()применяется, когда требуется параметр. Начните с базового классаRelayCommand<T>, который задействует классRelayCommand. Добавьте в папкуCommandBaseновый файл класса по имениCmds. Сделайте его открытым и укажитеRelayCommand.csв качестве базового класса. Добавьте две переменные уровня класса для хранения делегатовCommandBaseиExecute():CanExecute()private readonly Action _execute;private readonly Func<bool> _canExecute;Создайте три конструктора. Первый — стандартный конструктор (необходимый для производного класса
), второй — конструктор, который принимает параметрRelayCommand<T>, и третий — конструктор, принимающий параметрыActionиAction:Funcpublic RelayCommand(){}public RelayCommand(Action execute) : this(execute, null) { }public RelayCommand(Action execute, Func<bool> canExecute){_execute = execute?? throw new ArgumentNullException(nameof(execute));_canExecute = canExecute;}Наконец, реализуйте переопределенные версии
иCanExecute(). МетодExecute()возвращаетCanExecute(), если параметрtrueравенFunc; если же параметрnullнеFunc, то он выполняется и возвращаетсяnull. Методtrueвыполняет параметр типаExecute().Actionpublic override bool CanExecute(object parameter)=> _canExecute == null || _canExecute();public override void Execute(object parameter) { _execute(); }Создание класса RelayCommand<T>
Добавьте в папку
новый файл класса по имениCmds. КлассRelayCommandT.csявляется почти полной копией базового класса, исключая тот факт, что все делегаты принимают параметр. Сделайте класс открытым и обобщенным, а также унаследованным от базового классаRelayCommandT:RelayCommandpublic class RelayCommand<T> : RelayCommandДобавьте две переменные уровня класса для хранения делегатов
иExecute():CanExecute()private readonly Action<T> _execute;private readonly Func<T, bool> _canExecute;Создайте два конструктора. Первый из них принимает параметр
, а второй — параметрыAction<T>иAction<T>:Func<T,bool>public RelayCommand(Action<T> execute):this(execute, null) {}public RelayCommand(Action<T> execute, Func<T, bool> canExecute){_execute = execute?? throw new ArgumentNullException(nameof(execute));_canExecute = canExecute;}