.Net, C#, Uncategorized, UWP, WPF, xaml

ViewModelBase: go away.

So yeah, this isn’t directed at people doing cool Flux models with React.js, no, this is for those of use still plying the MVVM pattern with rich clients using XAML.

I hate “ViewModelBase”. “NotifyPropertyChangedBase”.  Whatever.  The basic thinking is, yeah, we do this a lot, let’s make a base class with all our common view model stuff.  Whatever.  I hate it.  Inheritance, is in most part, a trouble-making aspect of object orientation which for many cases can be avoided.

Composition makes your objects much more malleable, and this applies as much to your view model as elsewhere.

So yeah, it might cost a line or two extra, but we have CallerMemberName, and with C# 6.0 the amount of code required to implement  OnPropertyChanged is minimal:

private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

I get that property change methods can get tedious.  I’ve seen this code about a lot: the “Set” method which checks equality and makes the change.

But even so, enforcing an inheritance chain for this?  Pah.  Not interested.  I’ve see so many large enterprise systems creaking at their foundations due to cumbersome inheritance models that I just wont bother.  If you really want to encapsulate the check ‘n’ raise code, how about using an extension instead?  Something like this:

public static class NotifyPropertyChangedExtension
{
    public static void MutateVerbose<TField>(this INotifyPropertyChanged instance, ref TField field, TField newValue, Action<PropertyChangedEventArgs> raise, [CallerMemberName] string propertyName = null)
    {            
        if (EqualityComparer<TField>.Default.Equals(field, newValue)) return;
        field = newValue;
        raise?.Invoke(new PropertyChangedEventArgs(propertyName));            
    }
}

This means in your view model, yeah – you’ll have to declare the event, but I’ll take that one line over inheritance any day, and the final result is still pretty succinct:

public sealed class ViewModel : INotifyPropertyChanged
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            this.MutateVerbose(ref _name, value, args => PropertyChanged?.Invoke(this, args));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
Advertisement

4 thoughts on “ViewModelBase: go away.

  1. I haven’t seen any problems with using ViewModelBase. There have been no times where I would have liked to inherit from some other class. Can you provide an example where having a common base class (specifically in the VM) causes an issue?

    1. Inheritance issues aren’t specific to VMs. But why should you treat a VM different to any other class? The problems often caused by inheritance aren’t necessarily seen up front. Typically they might be picked up on by a developer years down the line who wants to refactor, modify, extend things only to find there path encumbered by seemingly innocent things done before.

      Of course inheritance has its uses, but I’ve seen all it’s worse aspects so always prefer composition first. That’s a how large systems live on, remain malleable, and responsive to change, whatever may happen in the future.

      So, for the sake of picking up one or two helper methods I just wont take a code base down that path, be it a VM layer, domain layer, server side or whatever else.

      https://en.wikipedia.org/wiki/Composition_over_inheritance

      1. While I agree with what you’ve said, I’m not convinced that VMs are not the right place for it. Like I said, I haven’t experienced any problems. In fact, having a common base class has actually helped in our framework (based on Caliburn.Micro). We have an entire hierarchy which serves our purposes just fine. If you have a concrete example where a base class for VMs cause issues, please share.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s