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; }