I believe you understood the design idea of MVVM with the introduction we made in the previous section. The main idea of MVVM is decomposition. View and ViewModel must be unaware of each other. While an entire architecture is executed with the incoming data, the View should only be concerned with rendering, and if the ViewModel, the Logic should be concerned with how it will do. Not only View and ViewModel, but also ViewModels must be decoupled from each other.
The core of the framework is the BindandleProperty class. All properties in the ViewModel that need to be bound to the UI controls must be BindableProperty. That class has only one responsibility. It monitors if the value of its Value has changed, and when it does it triggers the OnValuechanged event to alert the View.

public class BindableProperty<T>
{
    public delegate void ValueChangedHandler(T oldValue, T newValue);

    public ValueChangedHandler OnValueChanged;

    private T _value;
    public T Value
    {
        get
        {
            return _value;
        }
        set
        {
            if (!object.Equals(_value, value))
            {
                T old = _value;
                _value = value;
                ValueChanged(old, _value);
            }
        }
    }

    private void ValueChanged(T oldValue, T newValue)
    {
        if (OnValueChanged != null)
        {
            OnValueChanged(oldValue, newValue);
        }
    }
}

The question is: when and how will View monitor changes to these properties? BindableProperty is a very nice design. This can be used not only in the ViewModel but also in the View. Let’s use it to decorate the ViewModel. Whenever there is a change in the ViewModel, the ViewModel properties are monitored in a triggered event, such as initing, changing or assigning to another ViewModel. The abstract class that will be parent is defined as follows. UnityUIView:

public readonly BindableProperty<ViewModel> ViewModelProperty = new BindableProperty<ViewModel>();
public ViewModel BindingContext
{
    get { return ViewModelProperty.Value; }
    set { ViewModelProperty.Value = value; }
}

protected virtual void OnBindingContextChanged(ViewModel oldViewModel, ViewModel newViewModel)
{
}

public UnityUIView()
{
    this.ViewModelProperty.OnValueChanged += OnBindingContextChanged;
}

Subclass RegisterView inherited this parent class and override OnBindingContextChanged. Thus, while adding the callback-methods to the events of BindablePropertys, which are the monitoring mechanism, to the new ViewModel, it removed it from the old one!

protected override void OnBindingContextChanged(ViewModel oldViewModel, ViewModel newViewModel)
{

    base.OnBindingContextChanged(oldViewModel, newViewModel);

    SetupViewModel oldVm = oldViewModel as SetupViewModel;
    if (oldVm != null)
    {
        oldVm.Name.OnValueChanged -= NameValueChanged;
        ...
    }
    if (newViewModel!=null)
    {
        newViewModel.Name.OnValueChanged += NameValueChanged;
        ...
    }
}

More Abstract

Actually for the ViewModel there are a lot of BindablePropertys that need to be bound to the UI controls. In terms of code readability, the code below is both very long and verbose.

if (oldVm != null)
{
    oldVm.Name.OnValueChanged -= NameValueChanged;
    ...
}
if (ViewModel!=null)
{
    ViewModel.Name.OnValueChanged += NameValueChanged;
    ...
}

+= and -= pairs appear until OnValueChanged. This piece of code is almost *2. Is it possible to summarize this part of the code as a public class? If we take a closer look, the .OnValueChanged events or +=/-= handlers in each View seem like a blueprint that needs to be summarized.
For example, OnValueChanged events:

PropertyBindingUtils.Init<string>("Color",OnColorPropertyValueChanged);

Here +=/-= operations are inside the Init method. Thanks to Reflection technology, we can do this dynamically as follows. The entire process is not included here.

Init<TProperty>(string propertyName ,OnValueChanged valueChangedHandler)
{
	var fieldInfo = typeof(TViewModel).GetField(propertyName, BindingFlags.Instance | BindingFlags.Public);
	var value = fieldInfo.GetValue(viewModel);
	BindableProperty<TProperty> bindableProperty = value as BindableProperty<TProperty>;
	bindableProperty.OnValueChanged += valueChangedHandler;
	bindableProperty.OnValueChanged -= valueChangedHandler;
}

Refactor View Base Class: UnityUIView

Consider where the PropertyBinder should be placed.

Binder monitors property changes in ViewModel and replaces long oldVm.Property.OnValueChanged += and -= NameValueChanged code. So Binder must be defined inside View because every View needs it. Then we have to define it in UnityUIView. We’re making a small change to the BindingContext.

public readonly BindableProperty<ViewModelBase> ViewModelProperty = new BindableProperty<ViewModelBase>();
public ViewModelBase BindingContext
{
    get { return ViewModelProperty.Value; }
    set
    {
        if (!_isBindingContextInitialized)
        {
            OnInitialize();
            _isBindingContextInitialized = true;
        }
        ViewModelProperty.Value = value;
    }
}
/// <summary>
/// Instead of constructor
/// </summary>
protected virtual void OnInitialize()
{
    ViewModelProperty.OnValueChanged += OnBindingContextChanged;
}

We have made the OnInitialize method virtul because maybe the user wants to override and do some special follow-ups, for example:

protected override void OnInitialize()
{
    base.OnInitialize();
    Binder.Add<string>("Color",OnColorPropertyValueChanged);
}

private void OnColorPropertyValueChanged(string oldValue, string newValue)
{
    switch (newValue)
    {
        case "Red":
            buttonImage.color = Color.red;
            break;
        case "Yellow":
            buttonImage.color = Color.yellow;
            break;
        default:
            break;
    }
}