Всем привет! Сегодня расскажу, как с помощью применения новой технологии от Microsoft мы сможем упростить нашу ViewModel, избавиться от RelayCommand и в принципе сделаем наш код более читаемым.
В этой статье мы:
- Научимся добавлять nuget-пакеты
- Узнаем, как работают генераторы кода
- Расстроимся, что плагины под Ревит не поддерживают .NET (а только .NET Framework 4.8)
Дисклеймер: некоторые действия, приведённые в этой статье, могут показаться вам странными. Не переживайте: в следующей статье я расскажу про создание шаблонов Visual Studio, и повторять их в будущем особо не придётся.
Библиотека Community.Toolkit.Mvvm
Это библиотека, разработанная для создания WPF-приложений. Почитать о ней можно на официальном сайте Microsoft, или скачав приложение-образец, где в принципе рассказано тоже самое. Что умеет делать эта библиотека:
1. Генерирует свойства из полей. Как мы писали раньше для создания одного свойства:
private string _prefix = string.Empty;
public string Prefix
{
get => _prefix;
set
{
_prefix = value;
OnPropertyChanged();
}
}
А это 10 строчек кода. А ViewModel может быть очень большая в сложных плагинах. Существуют рекомендации, что файл класса не должен превышать 500 строк. А если у нас 25 переменных во ViewModel — сразу 250 строк занято.
Что мы пишем с Community.Toolkit.Mvvm:
[ObservableProperty] private string _prefix = string.Empty;
А остальное за нас дописывает генератор кода. Да, и создает публичное свойство Prefix. Да и ещё несколько методов создаёт, которые мы можем переопределить при необходимости:
Код от генератора лежит в отдельном файле и никак не мешает нам.
2. Генерирует команды (в том числе с параметром и асинхронные команды)
Нет, всё, отдельный RelayCommand, два обязательных метода для неё во ViewModel и публичное свойство, как мы делали в предыдущей части, писать не нужно. Просто перед методом, являющимся реализацией команды, пишем:
[RelayCommand]
или
[RelayCommand(CanExecute = nameof(YourCanExecute)]
И в вашей ViewModel появится публичной свойство с типом RelayCommand, с названием, равным названию вашего метода + слово Command.
3. Нет необходимости реализовывать INotifyPropertyChanged
Так же эта библиотека позволяет обмениваться сообщениями между классами и выполнять инъекцию зависимостей.
Подключение nuget-пакета
1. В Visual Studio проходим Средства — Диспетчер пакетов nuget — Управление пакетами nuget:
2. Устанавливаем пакет:
3. В обозревателе решений выделяем появившийся файл packages.config, жмём на него правой кнопкой мыши и выбираем "перенести в PackageReference":
4. Устанавливаем таким же образом пакет Microsoft.CodeDom.Providers.DotNetCompilerPlatform — это нужно для генераторов кода Roslyn.
5. В Обозревателе решений жмём правой кнопкой на Проект — Выгрузить проект:
6. Затем опять правой кнопкой мыши на выгруженный проект — Изменить файл проекта. Откроется файл csproj. Его надо отредактировать. Нам нужно перенести проект из обычного csproj в SDK-style csproj.
Перенос файла csproj в SDK-style
0. Делаем бэкап в соседнюю папку или коммит, если дружим с гитом. На всякий случай.
1. Установим .NET SDK по ссылке:
Далее изменим наш открытый csproj:
2. В самом начале удаляем первые 3 строки и пишем
<Project Sdk="Microsoft.NET.Sdk">
Сразу за ним идут PropertyGroup:
Особое внимание обратите на версию языка, она должна быть последней.
<LangVersion>latest</LangVersion>
3. Удаляем ItemGroup, в котором есть слово Compile. Если где-то осталась ссылка на наш xaml-файл, эту группу тоже удаляем.
4. Сохраняем csproj и перезагружаем проект с зависимостями (также через правую кнопку мыши)
5. В проекте находим файл AssemblyInfo (в папке Properties) и исключаем его из проекта.
Готово! Теперь можно использовать генераторы кода и все возможности Community.Toolkit.
Упрощение ViewModel
Осталась самая простая часть. Вместо реализации INotifyPropertyChanged выполним наследование от ObservableObject. Далее делаем следующее:
- Объявляем класс частичным: public partial class ViewModel : ObservableObject
- Перед приватными полями ставим атрибут [ObservableProperty].
- Перед методом Execute ставим атрибут [RelayCommand].
- У методов Execute и CanExecute удаляем (object parameter) из сигнатуры.
- В конце класса удаляем PropertyChanged и OnPropertyChanged (они уже есть в базовом классе).
- Удаляем публичные свойства, для которых есть приватные поля, и публичные свойства для команд.
Чтобы метод CanExecute работал правильно, надо добавить ещё немного атрибутов (распишу для своего примера с GitHub):
- [RelayCommand(CanExecute = nameof(CanNumerate))] вместо просто [RelayCommand].
- [NotifyCanExecuteChangedFor(nameof(NumerateCommand))] для приватных полей, рядом с [ObservableProperty] — у всех полей, значения которых обновляются в CanExecute.
Теперь выполним сборку и проверим результат в режиме отладки с помощью addin-менеджера. Доступность кнопок должна появляться лишь тогда, когда мы введём число в "Стартовый номер" и выберем параметр, и по нажатию кнопки "Запуск" команда должна отрабатывать штатно.
Результат
Мы узнали, как работают генераторы кода и научились подключать этот мощный инструмент к своим проектам.
Код ViewModel в примере сократился со 147 до 110 строк (и ещё можно удалить рукописный класс RelayCommand).
Итоговый код в моём репозитории на Github.
Подписывайтесь на мой телеграм-канал, не забывайте ставить лайки и звёздочки в репозитории. До новых встреч!