View
View — MonoBehaviour-компонент, связывающий UI-элементы с данными ViewModel через биндеры. Source Generator автоматически генерирует код инициализации и привязки.
Содержание
- Создание View
- Объявление биндеров
- Атрибут [AsBinder]
- Атрибут [BindId]
- Атрибут [IgnoreBind]
- Жизненный цикл
- IView<T> — строго типизированный View
- EventMonoView
- Instantiate
Создание View
using UnityEngine;
using Aspid.MVVM;
[View]
public sealed partial class PlayerView : MonoView
{
[SerializeField] private MonoBinder _health;
[SerializeField] private MonoBinder[] _name;
[SerializeField] private MonoBinder[] _attackCommand;
}
Обязательные условия:
- Класс должен быть
partial - Атрибут
[View] - Наследование от
MonoView
Правило именования
Имя поля (без префикса _, m_, s_) должно совпадать с именем свойства в ViewModel:
| Поле в View | Привязывается к свойству ViewModel |
|---|---|
_health | Health |
_name | Name |
_attackCommand | AttackCommand |
Одиночный vs массив
MonoBinder _field— один биндер. Удобно, когда точно один UI-элемент.MonoBinder[] _field— массив биндеров. Позволяет привязать несколько UI-элементов к одному свойству.
Объявление биндеров
Три способа объявления:
1. Через поля
[View]
public partial class ExampleView : MonoView
{
[SerializeField] private MonoBinder _name; // одиночный
[SerializeField] private MonoBinder[] _items; // массив
}
2. Через свойства
[View]
public partial class ExampleView : MonoView
{
private MonoBinder NameBinder { get; }
private MonoBinder[] ItemBinders { get; }
}
3. Через [AsBinder]
Оборачивает Unity-компонент в указанный тип биндера (см. ниже).
Атрибут [AsBinder]
Позволяет использовать Unity-компоненты напрямую как биндеры без добавления отдельного MonoBinder-компонента:
using UnityEngine.UI;
using Aspid.MVVM.StarterKit;
[View]
public partial class ExampleView : MonoView
{
// Image оборачивается в ImageSpriteBinder
[AsBinder(typeof(ImageSpriteBinder))]
private Image _icon;
// Массив Image оборачивается в ImageSpriteBinder[]
[AsBinder(typeof(ImageSpriteBinder))]
private Image[] _images;
}
Source Generator создаст код, который при инициализации создаёт ImageSpriteBinder из компонента Image.
Атрибут [BindId]
Переопределяет ID привязки для поля View:
[View]
public partial class ItemView : MonoView
{
// Привязка к свойству "Number" вместо "Name"
[BindId("Number")]
[SerializeField] private MonoBinder _name;
}
Можно комбинировать с [AsBinder]:
[View]
public partial class CustomView : MonoView
{
[BindId("PlayerIcon")]
[AsBinder(typeof(ImageSpriteBinder))]
private Image _icon;
}
Атрибут [IgnoreBind]
Исключает поле из автоматической привязки:
[View]
public partial class MixedView : MonoView
{
[SerializeField] private MonoBinder _name;
// Этот биндер НЕ будет привязан автоматически
[IgnoreBind]
[SerializeField] private MonoBinder _customBinder;
protected override void OnInitializedInternal()
{
// Ручная привязка
}
}
Жизненный цикл
Source Generator создаёт partial-методы для каждого этапа:
[View]
public partial class LifecycleView : MonoView
{
[SerializeField] private MonoBinder[] _data;
// ── Инициализация ──
// Перед привязкой биндеров
partial void OnInitializingInternal() { }
// После привязки всех биндеров
partial void OnInitializedInternal() { }
// ── Деинициализация ──
// Перед отвязкой биндеров
partial void OnDeinitializingInternal() { }
// После отвязки всех биндеров
partial void OnDeinitializedInternal() { }
// ── Создание массива биндеров ──
// Перед кэшированием биндеров
partial void OnInstantiatingBinders() { }
// После кэширования биндеров
partial void OnInstantiatedBinders() { }
}
Порядок вызова
OnInstantiatingBinders()/OnInstantiatedBinders()— однократно при первом InitializeOnInitializingInternal()— перед привязкой- Привязка каждого биндера через
FindBindableMember+Bind OnInitializedInternal()— после привязки- (работа)
OnDeinitializingInternal()— перед отвязкой- Отвязка каждого биндера через
Unbind OnDeinitializedInternal()— после отвязки
IView<T> — строго типизированный View
Для типобезопасной инициализации:
[View]
public partial class StrongView : MonoView, IView<PlayerViewModel>
{
[SerializeField] private MonoBinder[] _health;
public void Initialize(PlayerViewModel viewModel)
{
// Source Generator генерирует реализацию
}
}
Позволяет вызывать view.Initialize(playerVM) вместо view.Initialize((IViewModel)playerVM).
EventMonoView
Расширение MonoView с UnityEvent-ами для подписки через Inspector:
// В коде — просто наследуйте от EventMonoView
[View]
public partial class NotifyView : EventMonoView
{
[SerializeField] private MonoBinder _status;
}
В Inspector доступны события:
Initialized(IViewModel)— вызывается после инициализацииDeinitialized()— вызывается после деинициализации
Instantiate
Статический helper для создания View из префаба с немедленной инициализацией:
// Создать и инициализировать View из префаба
var view = MonoView.Instantiate(prefab, viewModel);
// С указанием родительского Transform
var view = MonoView.Instantiate(prefab, viewModel, parentTransform);
Инициализация и деинициализация
Из кода (Bootstrap-паттерн)
// Инициализация
_view.Initialize(viewModel);
// Деинициализация с освобождением ViewModel
_view.DeinitializeView()?.DisposeViewModel();
Через ViewInitializer (Inspector)
Без написания кода — через компонент ViewInitializer.
См. также
- ViewModel — создание ViewModel
- Биндеры — типы биндеров
- ViewInitializer — инициализация через Inspector