Туториал: Dynamic ViewModel
Разбор сэмпла Feature: Dynamic ViewModel — MVVM без генерации кода, для данных, форма которых известна только в рантайме.
Предполагается знание: Counter.
Когда это нужно
Свойства приходят из конфига, с сервера или из редактора уровней, и [ViewModel]-класса под них написать нельзя. DynamicViewModel объявляет свойства по строковому идентификатору, а биндеры находят их по тому же идентификатору.
Файлы: Samples~/DynamicViewModel/.
Секундомер
public sealed class StopwatchBootstrap : MonoBehaviour
{
[SerializeField] private MonoView _view;
private IDynamicProperty<string> _elapsed;
private IDynamicProperty<int> _laps;
private void Awake()
{
var viewModel = new DynamicViewModel();
viewModel.Add("Title", "Stopwatch", BindMode.OneTime);
_elapsed = viewModel.Add("Elapsed", Format(0f));
_laps = viewModel.Add("Laps", 0);
viewModel.Add<IRelayCommand>("LapCommand", new RelayCommand(() => _laps.Value++), BindMode.OneTime);
_view.Initialize(viewModel);
}
private void Update()
{
if (!_isRunning) return;
_seconds += Time.deltaTime;
_elapsed.Value = Format(_seconds);
}
}
Add<T>(id, value, mode)возвращаетIDynamicProperty<T>— дескриптор, через который значение читают и меняют. Биндеры следуют за ним.- Режим по умолчанию —
OneWay. Для команд и констант хватаетOneTime. - Команда — тоже значение:
Add<IRelayCommand>(...).
View без класса
В сцене стоит обычный MonoView. В его списке Binders каждому идентификатору (Title, Elapsed, Laps, LapCommand, …) сопоставлены биндеры и тип значения. Больше ничего: ни [View], ни [ViewModel], ни генератора.
Чего здесь нет
- Анализатора: опечатка в
"Elapsd"не найдётся на компиляции, только в рантайме. - Проверки типов на границе:
Add("Laps", 0)и биндер с типомstringразойдутся при первом же значении.
Поэтому DynamicViewModel — инструмент для действительно динамических данных, а не замена [ViewModel] ради экономии одного класса.
Подробнее — в Dynamic ViewModel.