Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

private ICommand _addCarCommand = null;

public ICommand AddCarCmd

=> _addCarCommand ??= new AddCarCommand);

Изменение файла MainWindow.xaml

Модифицируйте разметку XAML, удалив атрибут

Click
и добавив атрибуты
Command
и
CommandParameter
. Объект
AddCarCommand
будет получать список автомобилей из поля со списком
cboCars
. Ниже показана полная разметка XAML для кнопки:

<Button x:Name="btnAddCar" Content="Add Car" Margin="5,0,5,0" Padding="4, 2"

Command="{Binding Path=AddCarCmd,

RelativeSource={RelativeSource Mode=FindAncestor,

AncestorType={x:Type Window}}}"

CommandParameter="{Binding ElementName=cboCars, Path=ItemsSource}"/>

В

результате появляется возможность добавления автомобилей и обновления их цветов (пока с весьма ограниченной функциональностью) с помощью многократно используемого кода, содержащегося в автономных классах.

Изменение класса ChangeColorCommand

Финальным шагом будет обновление класса

ChangeColorCommand
, чтобы он стал унаследованным от
CommandBase
. Замените интерфейс
ICommand
классом
CommandBase
, добавьте к обоим методам ключевое слово
override
и удалите код события
CanExecuteChanged
. Все оказалось действительно настолько просто! Вот как выглядит новый код:

public 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
и
Func
:

public 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
выполняет параметр типа
Action
.

public override bool CanExecute(object parameter)

=> _canExecute == null || _canExecute;

public override void Execute(object parameter) { _execute; }

Создание класса RelayCommand<T>

Добавьте в папку

Cmds
новый файл класса по имени
RelayCommandT.cs
. Класс
RelayCommandT
является почти полной копией базового класса, исключая тот факт, что все делегаты принимают параметр. Сделайте класс открытым и обобщенным, а также унаследованным от базового класса
RelayCommand
:

public 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;

}

Наконец, реализуйте переопределенные версии

CanExecute
и
Execute
. Метод
CanExecute
возвращает
true
, если
Func
равно
null
, а иначе выполняет
Func
и возвращает
true
. Метод
Execute
выполняет параметр типа
Action
.

public override bool CanExecute(object parameter)

=> _canExecute == null || _canExecute((T)parameter);

public override void Execute(object parameter)

{ _execute((T)parameter); }

Изменение файла MainWindow.xaml.cs

Когда используются объекты

RelayCommand
, при конструировании новой команды должны указываться все методы для делегатов. Это вовсе не означает, что код нуждается в помещении внутрь файла отделенного кода (как показано здесь); он просто должен быть доступным из файла отделенного кода. Код может находиться в другом классе (или даже в другой сборке), что дает преимущества инкапсуляции, связанные с созданием специального класса команды.

Поделиться с друзьями: