Создание View Model
чтоб его создать нужен класс. Класс называют как View но с припиской VM или ViewModel это делается потому что так легко найти нужный файл
public partial class MainWindowVM : ObservableObject
{
}
он должен у наследоваться от ObservableObject или ObservableValidator
ObservableValidator нужен когда нужна валидация свойств он добавляет свойства и метод
и также класс должен быть частичным partial так как библиотека генерирует свой код для работы его можно увидеть если нажать CTRL + ЛКМ по имени типа класс покажется окно
так можно посмотреть что было сгенерировано
Атрибуты
у библиотеки есть несколько атрибутов для реализации VM
ObservableProperty
public partial class MainWindowVM : ObservableObject
{
[ObservableProperty]
private string _name;
[ObservableProperty]
private int _age;
}
это делается чтоб пометить поле для генератора которое уже сгенерирует полное свойство
генерирует он такое он такое
public string Name
{
get => _name;
[global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")]
set
{
if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(_name, value))
{
OnNameChanging(value);
OnNameChanging(default, value);
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
_name = value;
OnNameChanged(value);
OnNameChanged(default, value);
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
}
}
}
как можно увидеть в мести со свойством он генерирует частичные методы
- OnNameChanging(value) вызывается до присвоение нового значения свойства что позволяет отменить изменение
- OnNameChanging(oldValue,newValue) вызывается до присвоение нового значения свойства что позволяет отменить изменение но в отличие предаёт старое значение
- OnNameChanged(value) этот метод вызывается уже после присвоения передовая новое значение
- OnNameChanged(oldValue,newValue) этот метод вызывается уже после присвоения передовая новое значение но также передовая старое
Каждое поле с атрибутом [ObservableProperty] создаёт для каждого свойство и по 4 частичных методов
Что интересно Changing чтоб отменить изменение нужно выбросить исключение Пример:
partial void OnUserNameChanging(string oldValue, string newValue)
{
if (string.IsNullOrWhiteSpace(newValue))
{
// Можно выбросить исключение или установить флаг ошибки
throw new ArgumentException("Имя не может быть пустым");
}
if (newValue.Length > 20)
{
// Но можно выбросить исключение, чтобы SetProperty не выполнился
throw new ArgumentException("Максимум 20 символов");
}
}
RelayCommand
Этот атрибут нужен чтоб объявить команду для вызова метода
[RelayCommand]
private void Method()
{
}
[RelayCommand]
private async Task Method2Async()
{
}
Модификатор доступа тут не важен
тут генерируется публичный объект ICommand который привязывается к свойствам у элементов
что интересно: имя ICommand будет таким MethodCommamd берётся имя метода и добавляется слово Commamd и если у метода есть приставка Async то она стерпится и получится было Method2Async стало Method2Command тут надо аккуратней две одиновыми именами.
Важно:
методы не должны возвращать не тачего надо использовать либо void или Task для асинхронного кода ток Task должен быть без дженерика например Task<int> так нельзя.
Также у таких методов может быть максимум ток один параметр а иначе команда не сгенерируется.
Подключение
чтоб VM заработало нужно его присвоить
public MainWindow(MainWindowVM vm)
{
InitializeComponent();
DataContext = vm;
}
тут важен экземпляр класса как он будет получен зависит от вас
Важно:
Присвоение должно быть после вызова InitializeComponent();
Привязка (Binding)
<TextBox Text="{Binding Name}"/>
<Button Command="{Binding Method2Command}" Content="Моя команда"/>
Привязка осуществляется через слово "{Binding свойство}" при привязки нужно чтоб свойства были нужными типами
например для свойства Text у TextBox это string или любой числовой тип
а у элементов которые просто текст выводят Text принимает object то есть любой тип и вызовет ToString у него
а для свойства Command должен быть ICommand
В случаи не правильного со постановления типа будет ошибка компиляции что расскажет что не так
Большинства свойств умеют делать привязку а если не умеют нужно вручную менять свойства у VM через событие
И если типы разные у свойства VM и свойства элемента и вы хотите привязать его привязать то требуется конвертор