### Implement ScriptableViewModel with Bindings - C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/unity/scriptableviewmodel Demonstrates how to create a ViewModel by inheriting from ScriptableViewModel and using attributes like [ViewModel], [OneWayBind], [SerializeField], and [Min] for data binding and inspector integration. This example shows a basic setup for age and name properties. ```csharp using Aspid.MVVM; using UnityEditor; [ViewModel] public partial class MyScriptableViewModel : ScriptableViewModel { [OneWayBind] [SerializeField] [Min(0)] private int _age; [OneWayBind] [SerializeField] private string _name; } ``` -------------------------------- ### Aspid.MVVM RelayCommand Overloads Example (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/commands Demonstrates the usage of all five overloads of Aspid.MVVM's RelayCommand, catering to commands with zero to four parameters for both execution and condition checking. ```csharp using Aspid.MVVM; [ViewModel] public partial class MyViewModel { [Bind] private string _text; [Bind] private readonly IRelayCommand _command1; [Bind] private readonly IRelayCommand _command2; [Bind] private readonly IRelayCommand _command3; [Bind] private readonly IRelayCommand _command4; [Bind] private readonly IRelayCommand _command5; public MyViewModel() { _command1 = new RelayCommand(Do1, CanDo1); _command2 = new RelayCommand(Do2, CanDo2); _command3 = new RelayCommand(Do3, CanDo3); _command4 = new RelayCommand(Do4, CanDo4); _command5 = new RelayCommand(Do5, CanDo5); } private void Do1() => Text = "Command1"; private bool CanDo1() => true; private void Do2(int a) => Text = $"Command2 {a}"; private bool CanDo2(int a) => a > 0; private void Do3(int a, int b) => Text = $"Command3 {a}, {b}"; private bool CanDo3(int a, int b) => a + b < 100; private void Do4(int a, int b, int c) => Text = $"Command4 {a}, {b}, {c}"; private bool CanDo4(int a, int b, int c) => c > 0; private void Do5(int a, int b, int c, int d) => Text = $"Command5 {a}, {b}, {c}, {d}"; private bool CanDo5(int a, int b, int c, int d) => true; } ``` -------------------------------- ### Initialize View with ViewModel - C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/view Demonstrates the process of binding a View to a ViewModel by calling the Initialize method. This example requires a ViewModel marked with [ViewModel] and a View inheriting from MonoView. ```csharp using Aspid.MVVM; using UnityEngine; ​ [ViewModel] public partial class MyViewModel { } ​ [View] public partial class MyView : MonoView { } ​ public class Bootstrap { [SerializeField] private MyView _view; private void Awake() { _view.Initialize(new MyViewModel()); } } ``` -------------------------------- ### Configure Bootstrap Component in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvvm The Bootstrap component initializes the application by creating the Speaker model and setting up the views. It manages the lifecycle of the ViewModel and ensures proper deinitialization. ```csharp using System; using UnityEngine; public sealed class Bootstrap : MonoBehaviour { [Header("Views")] [SerializeField] private OutView _outView; [SerializeField] private InputView _inputView; private Speaker _speaker; private void Awake() { _speaker = new Speaker(); InitializeViews(); } private void OnDestroy() => DeinitializeViews(); private void InitializeViews() { var viewModel = new SpeakerViewModel(_speaker) _outView.Initialize(viewModel); _inputView.Initialize(viewModel); } private void DeinitializeViews() { _outView.DeinitializeView()?.DisposeViewModel(); _inputView.DeinitializeView()?.DisposeViewModel(); } } ``` -------------------------------- ### Aspid.MVVM [Access] Attribute Usage Example (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/viewmodel/binding-members/access Illustrates how to apply the [Access] attribute with the [Bind] attribute in a C# ViewModel. The example shows different combinations of access modifiers for getters and setters, overriding the default private access. ```csharp using Aspid.MVVM; [ViewModel] public partial class MyViewModel { // private string Text1 // { // get => _text1; // set => SetText1(value); // } [Bind] private string _text1; // public string Text2 // { // get => _text2; // set => SetText2(value); // } [Access(Access.Public)] [Bind] private string _text2; // protected string Text3 // { // get => _text3; // set => SetText3(value); // } [Access(Access.Protected)] [Bind] private string _text3; // public string Text4 // { // get => _text4; // private set => SetText4(value); // } [Access(Get = Access.Public)] [Bind] private string _text4; // protected string Text5 // { // get => _text5; // private set => SetText5(value); // } [Access(Get = Access.Protected)] [Bind] private string _text5; // public string Text6 // { // private get => _text6; // set => SetText6(value); // } [Access(Set = Access.Public)] [Bind] private string _text6; // protected string Text7 // { // private get => _text7; // set => SetText7(value); // } [Access(Set = Access.Protected)] [Bind] private string _text7; // public string Text8 // { // get => _text8; // protected set => SetText8(value); // } [Access(Get = Access.Public, Set = Access.Protected)] [Bind] private string _text8; // public string Text9 // { // protected get => _text9; // set => SetText9(value); // } [Access(Get = Access.Protected, Set = Access.Public)] [Bind] private string _text9; } ``` -------------------------------- ### ViewModel with [Bind] Attribute Example Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/viewmodel/binding-members/bind Demonstrates how to use the [Bind] attribute on constants and fields within a partial ViewModel class. The attribute enables the Source Generator to create bound properties. ```csharp using Aspid.MVVM; [ViewModel] public partial class MyViewModel { [Bind] private const int ConstValue = 1; [Bind] private int _value; [Bind] private readonly int _readonlyValue; } ``` -------------------------------- ### C# Model for Hello World in Aspid.MVVM Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world This C# code defines the 'Speaker' model, responsible for storing and managing text data. It includes a property 'Text' that notifies observers via the 'TextChanged' event when its value changes, and a 'Say' method to update the text. ```csharp using System; public class Speaker { public event Action TextChanged; private string _text; public string Text { get => _text; private set { _text = value; TextChanged?.Invoke(); } } public void Say(string text) => Text = text; } ``` -------------------------------- ### Binding Properties with IBinder (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/overview/overview-view Shows how to bind properties whose types implement IBinder. An example uses GameObjectVisibleBinder to enable/disable a GameObject based on a boolean value. ```csharp using Aspid.MVVM; using Aspid.MVVM.StarterKit; [View] public partial class MyView : MonoView { // GameObjectVisibleBinder is a binder that enables or disables // a GameObject based on a bool value. private GameObjectVisibleBinder IsVisible => new(gameObject); } ``` -------------------------------- ### Configure First Name ViewModel in Aspid.MVVM (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/introduction/getting-started/first-steps This C# code demonstrates how to configure a ViewModel to display a fixed name from a list. It uses the same `Names` class as the random name example but initializes the ViewModel with the first element of the `Names.Values` array. The `NameView` remains the same. Dependencies include Aspid.MVVM and UnityEngine. ```csharp using System.Collections.Generic; public static class Names { public static IReadOnlyList Values { get; } = new[] { "Vladislav", "Alexander", "Denis", }; } ``` ```csharp using System; using Aspid.MVVM; [ViewModel] [Serializable] public partial class FirstViewModel { [Bind] private readonly string _name = Names.Values[0]; } ``` ```csharp using Aspid.MVVM; using UnityEngine; [View] public partial class NameView : MonoView { [RequireBinder(typeof(string))] [SerializeField] private MonoBinder[] _name; } ``` -------------------------------- ### Generated Code for View Initialization and Binding Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/view/binder-members/field Provides an abstract example of the code generated by Aspid.MVVM for View initialization and binding. It showcases the Initialize, InitializeInternal, InstantiateBinders, BindSafely, and Deinitialize methods, along with partial methods for customization. ```csharp public partial class MyView : IView { private ViewBinder __childViewCachedBinder; public IViewModel ViewModel { get; private set; } public void Initialize(IViewModel viewModel) { if (viewModel is null) throw new ArgumentNullException(nameof(viewModel)); if (ViewModel is not null) throw new InvalidOperationException("View is already initialized."); ViewModel = viewModel; InitializeInternal(viewModel); } protected virtual void InitializeInternal(IViewModel viewModel) { OnInitializingInternal(viewModel); InstantiateBinders(); _name.BindSafely(viewModel.FindBindableMember(new(Ids.Name))); OnInitializedInternal(viewModel); } partial void OnInitializingInternal(IViewModel viewModel); partial void OnInitializedInternal(IViewModel viewModel); public void Deinitialize() { if (ViewModel is null) return; DeinitializeInternal(); ViewModel = null; } protected virtual void DeinitializeInternal() { OnDeinitializingInternal(); _name.UnbindSafely(); OnDeinitializedInternal(); } partial void OnDeinitializingInternal(); partial void OnDeinitializedInternal(); } ``` -------------------------------- ### Abstract Example of Generated RelayCommand Code (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/commands/relaycommand Provides a simplified, abstract representation of the C# code generated by the [RelayCommand] attribute. It illustrates how commands are initialized and linked to their corresponding methods and CanExecute logic. ```csharp public partial class MyViewModel { private RelayCommand _do1Command; private RelayCommand Do1Command => _do1Command ??= new(Do1); private RelayCommand _do2Command; private RelayCommand Do2Command => _do2Command ??= new(Do2, () => CanDo2); private RelayCommand _do3Command; private RelayCommand Do3Command => _do3Command ??= new(Do3, CanDo3); private RelayCommand _do4Command; private RelayCommand Do4Command => _do4Command ??= new(Do4, CanDo4); private RelayCommand _do5Command; private RelayCommand Do5Command => _do5Command ??= new(Do5, CanDo5); } ``` -------------------------------- ### Implement Multiple IBinder for Different Types in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/overview/overview-binders Shows how to extend a binder to support multiple data types by implementing multiple IBinder interfaces. This example adds support for float binding to a TextMonoBinder. ```csharp using TMPro; using Aspid.MVVM; using UnityEngine; using System.Globalization; public class TextMonoBinder : MonoBinder, IBinder, IBinder { [SerializeField] private TMP_Text _text; public void SetValue(float value) => SetValue(value.ToString(CultureInfo.InvariantCulture)); public void SetValue(string value) => _text.text = value; } ``` -------------------------------- ### Generate Binder with Additional Constructor Arguments Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/view/binder-members/asbinder This C# code shows how to use the [AsBinder] attribute with an overload that accepts additional arguments. These arguments are passed directly to the binder's constructor, allowing for more customized binder initialization. The example passes various data types as constructor parameters. ```csharp using Aspid.MVVM; using UnityEngine; using UnityEngine.UI; using Aspid.MVVM.StarterKit; [View] public partial class MyView : MonoView { [SerializeField] private bool _isActive; // Constructor: MyBinder => (Image, int, string, float, bool, bool) [AsBinder(typeof(MyBinder), 0, "some", 1.34f, nameof(_isActive), false)] [SerializeField] private Image _image; } ``` -------------------------------- ### Generate RelayCommand with Parameterized Execute and CanExecute Methods (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/overview/overview-commands This example demonstrates a RelayCommand where both the Execute and CanExecute methods accept parameters. The CanExecute method can optionally accept parameters matching those of the Execute method, or it can be a parameterless method if the execution status is independent of the parameters. This supports commands that operate on specific data. ```csharp using Aspid.MVVM; [ViewModel] public partial class MyViewModel { private bool IsActive => true; [RelayCommand(CanExecute = nameof(CanExecute1))] private void Execute1(int a) { } private bool CanExecute1(int a) => true; [RelayCommand(CanExecute = nameof(CanExecute2))] private void Execute2(int a) { } private bool CanExecute2() => true; [RelayCommand(CanExecute = nameof(IsActive))] private void Execute3(int a) { } } ``` -------------------------------- ### Aspid.MVVM [Access] Attribute Syntax Examples (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/viewmodel/binding-members/access Demonstrates the various ways to use the [Access] attribute to specify public, protected, or private access for both the getter and setter of a property. This attribute works in conjunction with the [Bind] attribute to control property visibility. ```csharp [Access(Access.Public)] // Public access for both get and set. [Access(Get = Access.Public)] // Public access for get only. [Access(Set = Access.Protected)] // Protected access for set only. [Access(Get = Access.Protected, Set = Access.Public)] // Combined access. ``` -------------------------------- ### Initialize and Manage Views with Bootstrap in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvvm The Bootstrap script in C# for Unity initializes and deinitializes UI Views and their corresponding ViewModels. It usesSerializeField to link Views and ViewModel types from the Inspector. The script handles view lifecycle events like Awake and OnDestroy, and allows for dynamic ViewModel creation based on an enum selection. ```csharp using System; using UnityEngine; public sealed class Bootstrap : MonoBehaviour { [Header("Views")] [SerializeField] private OutView _outView; [SerializeField] private InputView _inputView; [Header("ViewModel")] [SerializeField] private InputViewModelType _inputViewModelType; private Speaker _speaker; private void OnValidate() { if (!Application.isPlaying) return; if (!_outView || !_inputView || _speaker is null) return; DeinitializeViews(); InitializeViews(); } private void Awake() { _speaker = new Speaker(); InitializeViews(); } private void OnDestroy() => DeinitializeViews(); private void InitializeViews() { var viewModel = GetViewModel(); _outView.Initialize(viewModel); _inputView.Initialize(viewModel); } private void DeinitializeViews() { _outView.DeinitializeView()?.DisposeViewModel(); _inputView.DeinitializeView()?.DisposeViewModel(); } private IViewModel GetViewModel() => _inputViewModelType switch { InputViewModelType.Command => new SpeakerViewModel(_speaker), InputViewModelType.Moment => new MomentSpeakerViewModel(_speaker), _ => throw new ArgumentOutOfRangeException() }; private enum InputViewModelType { Moment, Command, } } ``` -------------------------------- ### Generate RelayCommand with CanExecute Method Reference (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/overview/overview-commands This example shows how to associate a CanExecute method with a RelayCommand using the CanExecute parameter in the attribute. The CanExecute method determines whether the command can be executed. The method name is provided as a string literal. ```csharp using Aspid.MVVM; [ViewModel] public partial class MyViewModel { [RelayCommand(CanExecute = nameof(CanExecute))] private void Execute() { } private void CanExecute() => true; } ``` -------------------------------- ### ViewModel Disposal (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/viewmodel Provides examples of how to dispose of a ViewModel. It shows checking if an `IViewModel` implements `IDisposable` and calling `Dispose()` manually, as well as using the provided extension method `DisposeViewModel()` for simplified resource cleanup. ```csharp IViewModel viewModel = ...; if (viewModel is IDisposable disposable) disposable.Dispose(); ``` ```csharp IViewModel viewModel = ...; viewModel.DisposeViewModel(); ``` -------------------------------- ### MomentInputViewMVP for Instant Input Updates in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvp The MomentInputViewMVP script handles instant text updates from a TMP_InputField in Unity. It exposes a TextChanged event that fires whenever the input field's value changes, allowing for real-time data binding. It also provides a Text property to get or set the input field's content. Dependencies include TMPro and UnityEngine. ```csharp using TMPro; using UnityEngine; using UnityEngine.Events; public class MomentInputViewMVP : MonoBehaviour { public event UnityAction TextChanged { add => _inputField.onValueChanged.AddListener(value); remove => _inputField.onValueChanged.RemoveListener(value); } [SerializeField] private TMP_InputField _inputField; public string Text { get => _inputField.text; set => _inputField.text = value; } } ``` -------------------------------- ### Bootstrap Component for Connecting MVVM - C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvvm Implements a Bootstrap class as a MonoBehaviour to connect Model, View, and ViewModel components. It initializes the Speaker model, creates a SpeakerViewModel, and then initializes the OutView and InputView with the ViewModel. It also handles deinitialization and ViewModel disposal. ```csharp using System; using UnityEngine; public sealed class Bootstrap : MonoBehaviour { [Header("Views")] [SerializeField] private OutView _outView; [SerializeField] private InputView _inputView; private Speaker _speaker; private void Awake() { _speaker = new Speaker(); InitializeViews(); } private void OnDestroy() => DeinitializeViews(); private void InitializeViews() { var viewModel = new SpeakerViewModel(_speaker) _outView.Initialize(viewModel); _inputView.Initialize(viewModel); } private void DeinitializeViews() { // You can use extension methods to deinitialize the View // and dispose of the ViewModel. _outView.DeinitializeView()?.DisposeViewModel(); _inputView.DeinitializeView()?.DisposeViewModel(); // Manual way to deinitialize the View and dispose of the ViewModel: // var viewModel = _outView.ViewModel; // _outView.Deinitialize(); // // if (viewModel is IDisposable disposable) // disposable.Dispose(); } } ``` -------------------------------- ### Create a Simple One-Way Binder with IBinder - C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/binder Demonstrates how to create a custom binder by inheriting from MonoBinder and implementing the IBinder interface for one-way binding. This example shows a TextMonoBinder that updates a TMP_Text component when a string value changes in the ViewModel. ```csharp using Aspid.MVVM; using UnityEngine; // MonoBinder implements IBinder and inherits from MonoBehaviour. public class TextMonoBinder : MonoBinder, IBinder { [SerializeField] private TMP_Text _text; // Called for OneWay, TwoWay, or OneTime binding. public void SetValue(string value) => _text.text = value; } ``` -------------------------------- ### Get an Empty RelayCommand Instance in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/commands Demonstrates how to obtain an instance of an empty RelayCommand using the static 'Empty' property. This is useful for commands that should never be executed. The 'Empty' property provides a performant way to access a single instance of an empty command. ```csharp var emptyCommand1 = RelayCommand.Empty; var emptyCommand2 = RelayCommand.Empty; ``` -------------------------------- ### Implement Multiple IBinder Interfaces for Different Types - C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/binder Illustrates how to extend a custom binder to support multiple data types by implementing multiple IBinder interfaces. This example enhances the TextMonoBinder to handle both string and float values, converting floats to strings before updating the text component. ```csharp using TMPro; using Aspid.MVVM; using UnityEngine; using System.Globalization; public class TextMonoBinder : MonoBinder, IBinder, IBinder { [SerializeField] private TMP_Text _text; public void SetValue(float value) => SetValue(value.ToString(CultureInfo.InvariantCulture)); public void SetValue(string value) => _text.text = value; } ``` -------------------------------- ### Example of a View with a GameObjectVisibleBinder Property Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/view/binder-members/property This C# code snippet demonstrates how to define a property in a View class that uses a `GameObjectVisibleBinder`. The binder's purpose is to enable or disable a GameObject based on a boolean value. Note the comment indicating that this property should not be used directly in code. ```csharp using Aspid.MVVM; using Aspid.MVVM.StarterKit; [View] public partial class MyView : MonoView { // Do not use directly in code! // GameObjectVisibleBinder is a binder that enables or disables // a GameObject based on a bool value. private GameObjectVisibleBinder IsVisible => new(gameObject); } ``` -------------------------------- ### MonoBinder with Multiple IBinder Implementations in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/unity/monobinder This C# example shows a TextMonoBinder that implements multiple IBinder interfaces (IBinder and IBinder). This allows the same binder to handle updates for different data types, converting integers to strings before updating the TextMeshProUGUI component. This enhances flexibility for binders that need to display various data formats. ```csharp using TMPro; using Aspid.MVVM; using UnityEngine; public class TextMonoBinder : MonoBinder, IBinder, IBinder { [SerializeField] private TMP_Text _text; public void SetValue(int value) => _text.text = value.ToString(); public void SetValue(string value) => _text.text = value; } ``` -------------------------------- ### InputViewMVP: Handle Text Input and Button Clicks in Unity Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvp The InputViewMVP script handles user text input and button interactions. It exposes a 'Clicked' event for button presses and provides a Text property to get or set the input field's content. This view is designed to notify its presenter of user actions. ```csharp using TMPro; using UnityEngine; using UnityEngine.UI; using UnityEngine.Events; public class InputViewMVP : MonoBehaviour { // Event to notify when the entered text should be read. public event UnityAction Clicked { add => _sayButton.onClick.AddListener(value); remove => _sayButton.onClick.RemoveListener(value); } // Button that signals to read the entered text when clicked. [SerializeField] private Button _sayButton; // Component to read the entered text from. [SerializeField] private TMP_InputField _inputField; // Public property to read or set the entered text. public string Text { get => _inputField.text; set => _inputField.text = value; } } ``` -------------------------------- ### Aspid.MVVM ViewModel Binding Example (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/viewmodel/binding-members Demonstrates how to apply various Aspid.MVVM binding attributes to ViewModel fields. It requires the ViewModel class to be marked with the [ViewModel] attribute and adherence to specific field naming conventions for ID generation. Currently supports fields and constants; properties and indexers are not directly supported but can be bound using [BindAlso]. ```csharp using Aspid.MVVM; [ViewModel] public partial class MyViewModel { [Bind] private int _age; [OneWayBind] private string _firstName; [TwoWayBind] private string _lastName; [OneTimeBind] private int _id; [OneWayToSource] private int _salary; } ``` -------------------------------- ### Bootstrap Component Initialization in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvp The Bootstrap script initializes MVP components and a Speaker in Unity. It sets up presenters for input and output views and ensures proper disposal of presenters when the GameObject is destroyed. Dependencies include OutViewMVP, InputViewMVP, and Speaker. ```csharp using System; using UnityEngine; public sealed class Bootstrap : MonoBehaviour { [Header("Out View")] [SerializeField] private OutViewMVP _outView; [Header("Input View")] [SerializeField] private InputViewMVP _inputView; private Speaker _speaker; private OutPresenterMVP _outPresenter; private InputPresenterMVP _inputPresenter; private void Awake() { _speaker = new Speaker(); _outPresenter = new OutPresenterMVP(_speaker, _outView); _inputPresenter = new InputPresenterMVP(_speaker, _inputView); } private void OnDestroy() { _outPresenter?.Dispose(); _inputPresenter?.Dispose(); } } ``` -------------------------------- ### Define InputView Component in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvvm This C# code defines the InputView class, inheriting from MonoView. It uses attributes like [View], [RequireBinder], and [SerializeField] to define input fields and commands, specifying their expected binder types. This setup is crucial for integrating with the Aspid.MVVM framework for handling user input and commands. ```csharp using Aspid.MVVM; using UnityEngine; [View] public sealed partial class InputView : MonoView { // _inputText can accept only one binder. // This approach is convenient when we know there will be exactly one binding element. [RequireBinder(typeof(string))] [SerializeField] private MonoBinder _inputText; // _sayCommand is declared as an array, which is convenient // as it allows attaching an unlimited number of binding elements. [RequireBinder(typeof(IRelayCommand))] [SerializeField] private MonoBinder[] _sayCommand; } ``` -------------------------------- ### Define OutView Component in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvvm OutView is a Unity MonoView responsible for displaying output text. It requires a string binder to display the text from the ViewModel. ```csharp using Aspid.MVVM; using UnityEngine; [View] public sealed partial class OutView : MonoView { [RequireBinder(typeof(string))] [SerializeField] private MonoBinder[] _outText; } ``` -------------------------------- ### Bootstrap Component for View Initialization (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/introduction/getting-started/first-steps A MonoBehaviour that initializes the `NameView` by creating a `RandomNameViewModel` and linking them. It handles view initialization and deinitialization. ```csharp using UnityEngine; public sealed class Bootstrap : MonoBehaviour { [SerializeField] private NameView _view; private void Awake() { var viewModel = new RandomNameViewModel(); _view.Initialize(viewModel); } private void OnDestroy() { _view.Deinitialize(); } } ``` -------------------------------- ### Strongly-Typed ViewModel Initialization (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/view/iview-less-than-t-greater-than Shows the recommended approach for initializing a View with a ViewModel when the exact type is known. This uses the strongly-typed Initialize method to avoid potential multiple type checks. ```csharp MyViewModel viewModel = GetViewModel(); myView.Initialize(viewModel); ``` -------------------------------- ### Define SpeakerViewModel in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvvm SpeakerViewModel connects the Speaker model to the Views using MVVM patterns. It handles one-way and two-way data binding and implements IDisposable for cleanup. ```csharp using System; using Aspid.MVVM; [ViewModel] public sealed partial class SpeakerViewModel : IDisposable { [OneWayBind] private string _outText; [TwoWayBind] private string _inputText; private readonly Speaker _speaker; public SpeakerViewModel(Speaker speaker) { _speaker = speaker; _outText = speaker.Text; _inputText = speaker.Text; _speaker.TextChanged += SetOutText; } [RelayCommand] private void Say() { _speaker.Say(InputText); } public void Dispose() => _speaker.TextChanged -= SetOutText; } ``` -------------------------------- ### Implement Basic View Lifecycle Handlers in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/view/handlers Demonstrates how to implement optional partial methods for the View lifecycle in C#. These methods are called at specific points during a View's initialization and deinitialization, allowing for custom behavior injection. ```csharp using Aspid.MVVM; [View] public partial class MyView { // Called before View initialization. partial void OnInitializingInternal(IViewModel viewModel) { } // Called after View initialization. partial void OnInitializedInternal(IViewModel viewModel) { } // Called before View deinitialization. partial void OnDeinitializingInternal() { } // Called after View deinitialization. partial void OnDeinitializedInternal() { } } ``` -------------------------------- ### Modify Bootstrap for Instant Input View Updates (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvp This C# code snippet shows the modified Bootstrap component. It initializes the Speaker, OutPresenterMVP, and MomentInputPresenterMVP. The `OutViewMVP` and `MomentInputViewMVP` are designed to update instantly from the `InputField` without requiring a button press. Dependencies include Unity Engine and TMPro. ```csharp using System; using UnityEngine; public sealed class Bootstrap : MonoBehaviour { [Header("Out View")] [SerializeField] private OutViewMVP _outView; [Header("Input View")] [SerializeField] private MomentInputViewMVP _inputView; private Speaker _speaker; private OutPresenterMVP _outPresenter; private MomentInputPresenterMVP _inputPresenter; private void Awake() { _speaker = new Speaker(); _outPresenter = new OutPresenterMVP(_speaker, _outView); _inputPresenter = new MomentInputPresenterMVP(_speaker, _inputView); } private void OnDestroy() { _outPresenter.Dispose(); _inputPresenter.Dispose(); } } ``` -------------------------------- ### Define InputView Component in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvvm InputView is a Unity MonoView for handling user input. It includes a string binder for text input and a binder for a relay command to trigger an action. ```csharp using Aspid.MVVM; using UnityEngine; [View] public sealed partial class InputView : MonoView { [RequireBinder(typeof(string))] [SerializeField] private MonoBinder _inputText; [RequireBinder(typeof(IRelayCommand))] [SerializeField] private MonoBinder[] _sayCommand; } ``` -------------------------------- ### Create Command Without Parameters (C# - Without Extension) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/commands/extensions Demonstrates creating a parameterless command from an existing command with parameters without using the CreateCommandWithoutParametersOrEmpty extension method. This approach involves manually checking for null and providing appropriate command implementations. ```csharp #nullable enable using Aspid.MVVM; [ViewModel] public partial class MyViewModel { [OneTimeBind] private readonly IRelayCommand _command; public MyViewModel(IRelayCommand? command) { if (command is null) _command = RelayCommand.Empty; else _command = new RelayCommand( () => command.Execute(this), () => command.CanExecute(this)); } } ``` -------------------------------- ### Generate RelayCommands from ViewModel Methods (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/commands/relaycommand Demonstrates how to use the [RelayCommand] attribute to automatically generate commands from methods within a ViewModel. This includes examples with and without parameters, and with conditional execution logic. ```csharp using Aspid.MVVM; [ViewModel] public partial class MyViewModel { [Bind] private string _text; [RelayCommand(CanExecute = nameof(CanDo1))] private void Do1() => Text = "Command1"; private bool CanDo1() => true; [RelayCommand(CanExecute = nameof(CanDo2))] private void Do2(int arg1) => Text = $"Command2 {arg1}"; private bool CanDo2(int arg1) => arg1 > 0; [RelayCommand(CanExecute = nameof(CanDo3))] private void Do3(int a, int b) => Text = $"Command3 {a}, {b}"; private bool CanDo3(int a, int b) => a + b < 100; [RelayCommand(CanExecute = nameof(CanDo4))] private void Do4(int a, int b, int c) => Text = $"Command4 {a}, {b}, {c}"; private bool CanDo4(int a, int b, int c) => c > 0; [RelayCommand(CanExecute = nameof(CanDo5))] private void Do5(int a, int b, int c, int d) => Text = $"Command5 {a}, {b}, {c}, {d}"; private bool CanDo5(int a, int b, int c, int d) => true; } ``` -------------------------------- ### Bootstrap View and ViewModel Binding in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/introduction/getting-started/first-steps A `Bootstrap` MonoBehaviour class that initializes `NameView` with an instance of `RandomNameViewModel` in `Awake`. It also handles unbinding in `OnDestroy` using `Deinitialize()`. Requires UnityEngine. ```csharp using UnityEngine; public sealed class Bootstrap : MonoBehaviour { [SerializeField] private NameView _view; private void Awake() { var viewModel = new RandomNameViewModel(); // The View can be initialized with any ViewModel. _view.Initialize(viewModel); } private void OnDestroy() { // To unbind the ViewModel from the View, call Deinitialize(). _view.Deinitialize(); } } ``` -------------------------------- ### C# ViewModel: SpeakerViewModel Class Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvvm A ViewModel for 'Speaker', implementing 'IDisposable'. It uses '[OneWayBind]' for '_outText' and '[TwoWayBind]' for '_inputText', linking to the 'Speaker' model. It includes a 'Say' command to update the speaker's text. ```csharp using System; using Aspid.MVVM; [ViewModel] public sealed partial class SpeakerViewModel : IDisposable { [OneWayBind] private string _outText; [TwoWayBind] private string _inputText; private readonly Speaker _speaker; public SpeakerViewModel(Speaker speaker) { _speaker = speaker; _outText = speaker.Text; _inputText = speaker.Text; _speaker.TextChanged += SetOutText; } [RelayCommand] private void Say() => _speaker.Say(InputText); public void Dispose() => _speaker.TextChanged -= SetOutText; } ``` -------------------------------- ### C# ViewModel: MomentSpeakerViewModel Class Source: https://vpd-inc.gitbook.io/aspid.mvvm/tutorials/hello-world/mvvm A ViewModel similar to 'SpeakerViewModel' but designed for immediate text updates. It binds '_outText' and '_inputText' and uses 'OnInputTextChanged' to call '_speaker.Say' directly upon input changes, without an explicit command. ```csharp using System; using Aspid.MVVM; [ViewModel] public sealed partial class MomentSpeakerViewModel : IDisposable { [OneWayBind] private string _outText; [TwoWayBind] private string _inputText; private readonly Speaker _speaker; public MomentSpeakerViewModel(Speaker speaker) { _speaker = speaker; _outText = speaker.Text; _inputText = speaker.Text; _speaker.TextChanged += SetOutText; } partial void OnInputTextChanged(string newValue) => _speaker.Say(newValue); public void Dispose() => _speaker.TextChanged -= SetOutText; } ``` -------------------------------- ### Configure Random Name ViewModel in Aspid.MVVM (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/introduction/getting-started/first-steps This C# code demonstrates how to configure a ViewModel to display a random name. It includes a static `Names` class for a list of names, a `RandomNameViewModel` that selects a name randomly on initialization, and a `NameView` to display the name. Dependencies include Aspid.MVVM and UnityEngine. ```csharp using System.Collections.Generic; public static class Names { public static IReadOnlyList Values { get; } = new[] { "Vladislav", "Alexander", "Denis", }; } ``` ```csharp using System; using Aspid.MVVM; using Aspid.MVVM.StarterKit; using Random = UnityEngine.Random; [ViewModel] [Serializable] public partial class RandomNameViewModel : IComponentInitializable { [Bind] private string _name; public void Initialize() { var names = Names.Values; Name = names[Random.Range(0, names.Count)]; } } ``` ```csharp using Aspid.MVVM; using UnityEngine; using Aspid.MVVM.Unity; [View] public partial class NameView : MonoView { [RequireBinder(typeof(string))] [SerializeField] private MonoBinder[] _name; } ``` -------------------------------- ### Override Bind Modes with BindModeOverride Attribute Source: https://vpd-inc.gitbook.io/aspid.mvvm/overview/overview-binders These C# examples show how to use the [BindModeOverride] attribute to control which binding modes are selectable in the Unity Inspector. Different overloads allow for selecting all modes, specific combinations, or individual modes. ```csharp // Allows any binding mode to be selected in the Inspector. [BindModeOverride(IsAll = true)] ``` ```csharp // Allows OneWay and OneTime binding modes to be selected in the Inspector. [BindModeOverride(IsOne = true)] ``` ```csharp // Allows TwoWay and OneWayToSource binding modes to be selected in the Inspector. [BindModeOverride(IsTwo = true)] ``` ```csharp // Allows only the OneTime binding mode to be selected in the Inspector. [BindModeOverride(BindMode.OneTime)] ``` -------------------------------- ### Create Command Without Parameters (C# - With Extension) Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/commands/extensions Illustrates the usage of the CreateCommandWithoutParametersOrEmpty extension method for creating a parameterless command. This method simplifies the code by abstracting the null check and command creation logic, making the ViewModel constructor more concise. ```csharp #nullable enable using Aspid.MVVM; [ViewModel] public partial class MyViewModel { [OneTimeBind] private readonly IRelayCommand _command; public MyViewModel(IRelayCommand? command) { _command = command.CreateCommandWithoutParametersOrEmpty(this); } } ``` -------------------------------- ### Create RelayCommand in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/overview/overview-commands Demonstrates the basic instantiation of a RelayCommand with execute and can-execute methods. This command pattern is central to MVVM architectures for handling user interactions. ```csharp using Aspid.MVVM; [ViewModel] public partial class MyViewModel { [OneWayBind] private readonly IRelayCommand _command; public MyViewModel() { _command = new RelayCommand(Execute, CanExecute); } private void Execute() { } private bool CanExecute() => true; } ``` -------------------------------- ### Combine IAnyBinder and IBinder for Specific Type Overrides in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/overview/overview-binders Demonstrates how to combine IAnyBinder with a specific IBinder implementation to override behavior for a particular data type. This example provides specific formatting for float values while using the generic handler for others. ```csharp using TMPro; using Aspid.MVVM; using UnityEngine; using System.Globalization; public class TextMonoBinder : MonoBinder, IBinder, IAnyBinder { [SerializeField] private TMP_Text _text; // Called if the incoming value is not float. public void SetValue(T value) => _text.text = value.ToString(); // Called if the incoming value is float. public void SetValue(float value) => _text.text = value.ToString(CultureInfo.InvariantCulture); } ``` -------------------------------- ### Enhance RandomNameViewModel for Serialization (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/introduction/getting-started/first-steps An enhanced `RandomNameViewModel` that implements `IComponentInitializable` for proper serialization and initialization. It uses `[Serializable]` and initializes the name during `Initialize()`. ```csharp using System; using Aspid.MVVM; using Aspid.MVVM.StarterKit.Unity; using Random = UnityEngine.Random; [ViewModel] [Serializable] public partial class RandomNameViewModel : IComponentInitializable { // Since field initialization no longer occurs in the constructor, // remove the readonly keyword. [Bind] private string _name; public void Initialize() { var names = Names.Values; // Outside the constructor, use the generated Name property // to ensure binding works correctly. Name = names[Random.Range(0, names.Count)]; } } ``` -------------------------------- ### Create FirstNameViewModel (C#) Source: https://vpd-inc.gitbook.io/aspid.mvvm/introduction/getting-started/first-steps A ViewModel that always binds to the first name in the `Names.Values` list. It is marked as `[Serializable]` and `[ViewModel]`. ```csharp using System; using Aspid.MVVM; [ViewModel] [Serializable] public partial class FirstNameViewModel { [Bind] private readonly string _name = Names.Values[0]; } ``` -------------------------------- ### Prevent Duplicate Binder Initialization Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/view/binder-members/ignore-generation The Aspid MVVM generator attempts to prevent cases where a binder's Bind method would be called twice. This example shows how a private property, excluded from generation, can prevent a binder from being initialized twice. ```csharp using Aspid.MVVM; using UnityEngine; [View] public partial class MyView : MonoView { [SerializeField] private MonoBinder _binder; // Excluded from generation to prevent the binder // from being initialized twice. private MonoBinder Binder1 => _binder; } ``` -------------------------------- ### Implement Binder Lifecycle Handlers in C# Source: https://vpd-inc.gitbook.io/aspid.mvvm/documentation/view/handlers Shows how to implement additional partial methods for View lifecycle events related to binder instantiation in C#. These methods are generated when the View contains properties implementing IBinder or IView, fields implementing IView, or fields/properties with the [AsBinder] attribute. ```csharp using Aspid.MVVM; [View] public partial class MyView { // Called before caching binders partial void OnInstantiatingBinders(); // Called after caching binders partial void OnInstantiatedBinders(); } ```