Let’s start simple – SimpleViewModelBase

Let’s start simple – SimpleViewModelBase

To implement the MVVM (Model-View-ViewModel) pattern, you need ViewModels that implement the INotifyPropertyChanged Interface.

I normally handle this by having a base class for all ViewModels to inherit.

public abstract class SimpleViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
 
    public void OnPropertyChanged([CallerMemberNamestring propertyName = "")
    {
        PropertyChanged?.Invoke(this,
                        new PropertyChangedEventArgs(propertyName));
    }
 
    public bool setBackingField<T>(ref T storage, 
                                   T value,
                                   [CallerMemberNamestring propertyName = "")
    {
        var oldValue = storage;
 
        if(object.Equals(storage, value))
        {
            return false;
        }
 
        storage = value;
 
        OnPropertyChanged(propertyName);
 
        return true;
    }
}

OnPropertyChanged() will either allow for a property to announce that it has changed

public string MyProperty
{
    get { return _myProperty; }
    set
    {
        _myProperty = value;
        OnPropertyChanged();
    }
}

..or that another property has changed, by passing the name of that property.

public string LastName
{
    set
    {
        ...
        OnPropertyChanged(nameof(FullName));
    }
}

setBackingField<T>() is a helper method to allow property setters to perform all of the aspect necessary for setting their backing field and calling OnPropertyChanged to reflect that change.

public string MyProperty
{
    get { return _myProperty; }
    set
    {
        setBackingField(ref _myProperty, value);
    }
}

setBackingField<T>() will return a boolean informing if there was change.

ViewModels will inherit this and take advantage of the helper methods

public class PersonViewModel : SimpleViewModelBase
{
    private string _firstName;
    public string FirstName
    {
        get => _firstName;
        set
        {
            if (setBackingField(ref _firstName, value))
            {
                //Also inform Fullname
                OnPropertyChanged(nameof(FullName));
            }
        }
    }
 
    private string _lastName;
    public string LastName
    {
        get => _lastName;
        set
        {
            if (setBackingField(ref _lastName, value))
            {
                //Also inform Fullname
                OnPropertyChanged(nameof(FullName));
            }
        }
    }
 
    public string FullName
    {
        get => $"{FirstName} {LastName}";
    }
}

Leave a Reply