Getting Started
A step-by-step guide from installation to the first working example.
Contents
Requirements
- Unity 2022.3 or newer
- .NET Standard 2.0 (the framework's target)
- Source Generators support in Unity (built in since 2022.3)
Installation
From the Unity Asset Store
- Open the Aspid.MVVM page in the Unity Asset Store
- Import the package into your project
- Make sure the
Assets/Aspid/MVVM/folder was created
From source
git clone https://github.com/VPDPersonal/Aspid.MVVM.git
cd Aspid.MVVM
git submodule update --init --recursive
The project uses git submodules. Without git submodule update --init --recursive the code does not compile.
Learning path
Each sample adds exactly one new concept. Every sample's README.md is its tutorial.
| # | Sample | New | Tutorial |
|---|---|---|---|
| 1 | Counter | [ViewModel], [Bind], [RelayCommand], ViewInitializer | Counter |
| 2 | Greeter | MonoViewModel, [TwoWayBind], [BindAlso], On*Changed | Greeter |
| 3 | Bind Modes | four modes on one screen, your own ITwoWayConverter | Bind Modes |
| 4 | Stats | commands with a parameter, CanExecute, draft → model | Stats |
| 5 | Todo List | a model, ObservableList, CreateSync, collection binders | Todo List |
| 6 | Custom Binder | a binder for your own component, [GenerateSerializableBinder] | Custom Binder |
First example: Counter
A button increments a counter and the number is shown in a text. The smallest example that shows the three core concepts of the framework.
Step 1: ViewModel
The ViewModel holds data and logic. The Source Generator writes all the binding code.
using Aspid.MVVM;
// [ViewModel] marks the class for the Source Generator.
// The class must be partial.
[ViewModel]
public sealed partial class CounterViewModel
{
// [OneWayBind]: data flows from the ViewModel to the View only.
// The generator emits a Count property whose setter notifies binders.
[OneWayBind] private int _count;
// [RelayCommand]: the generator emits an IncrementCommand property of type IRelayCommand.
[RelayCommand]
private void Increment() => Count++;
}
What the Source Generator produces:
| Source | Generated |
|---|---|
[ViewModel] on the class | IViewModel implementation, FindBindableMember |
[OneWayBind] int _count | Count property with a notifying setter, OnCountChanging / OnCountChanged hooks |
[RelayCommand] void Increment() | IncrementCommand property of type IRelayCommand |
Step 2: View
The View declares which binders connect to which ViewModel members.
using UnityEngine;
using Aspid.MVVM;
// [View] marks the class for the Source Generator.
// The class must be partial.
[View]
public sealed partial class CounterView : MonoView
{
// The field name matches the ViewModel field name.
// The generator binds them by name.
[SerializeField] private MonoBinder _count;
// An array of binders: several UI elements trigger the same action.
[SerializeField] private MonoBinder[] _increment;
}
Naming rule: the View field name without the _, m_ or s_ prefix must match the ViewModel member. _count binds to Count.
Step 3: Bootstrap
Bootstrap connects the View and the ViewModel:
using UnityEngine;
using Aspid.MVVM;
public sealed class Bootstrap : MonoBehaviour
{
[SerializeField] private CounterView _counterView;
private void Awake()
{
var viewModel = new CounterViewModel();
_counterView.Initialize(viewModel);
}
private void OnDestroy()
{
_counterView.DeinitializeView()?.DisposeViewModel();
}
}
Step 4: Inspector setup
- Create a GameObject with the
CounterViewcomponent - Add a child with a
TextMonoBinderand drag it into the_countfield - Add a child with a
Buttonand aButtonCommandMonoBinderand drag it into the_incrementarray - On the Bootstrap object assign the
CounterViewreference
How it works
After view.Initialize(viewModel):
- View walks its binders and calls
viewModel.FindBindableMember(id)for each - ViewModel (generated code) finds the
BindableMemberby id without reflection - Binder subscribes and receives the current value
- When
Countchanges, the binder updates theText - When the button is pressed,
ButtonCommandMonoBindercallsIncrementCommand.Execute()
ViewModel ──► BindableMember ──► Binder ──► UI
(no reflection, direct calls)
The Source Generator emits direct calls at compile time: no reflection, no allocations.
Next steps
- Counter, the full tutorial with binder details
- Greeter, two-way binding: InputField → Text in real time
- Architecture, the binding pipeline in detail
- Binding Modes: OneWay, TwoWay, OneTime, OneWayToSource
- StarterKit, every ready-made binder for Unity UI