MVVM – Model

She’s a Model and She’s Looking Good

In this post, I’m going to start the refactoring of the StaffManager demonstration application, by looking at the Model elements.

Looking at the Person class I introduced in part 1 of this series, there are several options available to improve things. Even in such a basic application, there are already two implementations of INotifyPropertyChanged – in the Person model class and MainViewModel. This is a prime example of W.E.T. (write everything twice) programming. A cleaner solution would be the complete opposite – D.R.Y. (don’t repeat yourself).

This is a perfect opportunity to introduce the MVVMLight toolkit. As I said in the introduction to this series, you don’t have to use a library to implement MVVM. However, my experience is that MVVMLight provides just enough of a framework to use as a starting point, without imposing itself and taking over the entire application structure.

The first helper class I’ll look at is ObservableObject, which I’m going to use as the ultimate base class for both Models and ViewModels. The MVVMLight source code does look a little complicated, as it’s a multi-platform library, but you don’t need to worry about that. Install MVVMLight via Nuget, and it will automatically pick the correct version for your project. I suggest that you use the MVVMLightLibs variant though, which just installs the required DLLs – the full MVVMLight package will modify your application structure slightly (e.g. by adding a ViewModelLocator object – more on that in a future post).

ObservableObject contains two key elements, along with a few additional utility methods.

  • An INotifyPropertyChanged implementation, very similar to what I had in my own classes.
  • A Set() method, which greatly simplifies how properties are coded in the class.

Using this Set() method, you still need a private backing field, but the check for equality, the assignment and raising the propertychanged event are now combined into a single statement.

    private string _firstName;

    public string FirstName
        get { return _firstName; }
        set { Set(nameof(FirstName), ref _firstName, value); }

The Set() method returns true when the property value actually changes, allowing further processing in the property setter as required.

Note that there is also an overridden version of Set(), which takes a Expression<Func<T>> (usually coded as a lambda expression) to obtain the property name …

    set { Set(() => FirstName, ref _firstName, value); }

… but this has been superseded in more recent versions of C# by using nameof().

Writing property setters as …

    set { Set("FirstName", ref _firstName, value); }

… along with other hard-coded “magic strings”, is a Bad Thing™, and should be avoided at all costs. With this construct it’s just too easy to forget to change the strings when you modify property names, which will leave you tearing your hair out when your data-bindings don’t update as expected. Using nameof() or a lambda expression will trap such errors at compile time.

Some MVVM commentators suggest the use of CallerMemberName as a means to avoid passing the property name altogether. Personally, I prefer to be explicit and unambiguous though, even if it does make the code slightly more verbose. This is because many of the calls to RaisePropertyChanged still require a property name (as they reference a property other than the one being set)

Who does what?

There is much debate in the MVVM world over the exact division of labour between Model and ViewModel layers in an application. My personal view is that model classes should be completely dumb (with one exception which I’ll deal with in a future post). As an old-school relational database developer, I like having my models mirror what is stored in the persistence layer of the application. Those of you working with document-style (NoSql) databases may take a different viewpoint. I actually go so far as to use exactly the same model classes for code-first database schema definitions, and for transport objects for web and other services. Having the model classes split out into their own project – StaffManager.Model in the case of our demo application, allows any other projects within the solution to use them with minimal dependencies.

There are two properties within our Person class that don’t fit with this viewpoint – DisplayName and IsSelected. I’ll leave those non-data properties in place for now, but the next post will offer a means to deal with them.

You may have noticed in the demo application that there are two intermediate model classes, one in the library (perModelBase) and another (smModelBase) in StaffManager.Model. I’ll leave both of those empty for now, dealing with the reasons why they exist in future posts.

Situation Normal?

Anyone who’s an experienced database user will have spotted a flaw with the data model in the original version of StaffManager. The department field already contains multiple variations for the same entity, “IT” and “I.T.”, and leaving this is a plain text field will likely lead to further discrepancies in the future. As an aside, I once had to do an analysis of postal address data, to identify people from USA, and even with a specific country field (plain text though), there were 47 different variations that I found (“USA”, “U.S.A.”, “United States” etc). To keep your sanity, don’t use plain text for any data you want to do analysis on. In the database world this would be a perfect candidate for normalisation, so I’m going to do the same with the models. I’ve split the department data out into a separate class, and just having a referencing DepartmentId property on the Person class. To keep the application functional during the refactoring, I’ll also add a Department property to the person Model, but that will be removed in a future update.

To fit with our new ‘normalised’ data model, the person editing panel on the main view has been updated to use a ComboBox to select the person’s department from a fixed list of values. perValueDisplayPair is a handy alternative to KeyValuePair, with more memorable names, designed for ComboBox binding.

Size Zero Model

Even with the slimmed down variation of the properties, as outlined above, the code is still quite verbose. It’s not so bad when there only 5 actual data properties, but imagine typing all that boilerplate code for 20, 50, or in an extreme case 200 plus properties on a model class. What if I could just write the Model class like this …

    public class Person: smModelBase
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int DepartmentId { get; set; }
        public bool IsManager { get; set; }

        // non-data properties, to be removed ...
        public string DisplayName => FirstName + " " + LastName;
        public Department Department { get; set; }
        public bool IsSelected { get; set; }

… and still have all the INotifyPropertyChanged stuff working, even for the calculated DisplayName property. Is this really possible, or just a programmer’s dream?

I’m not usually a fan of programming techniques that happen by “magic”. When using someone else’s code, I like to step through it in Visual Studio at least once, just to see how it works. However, in this one case I’m prepared to make an exception. This particular helping hand is called Fody PropertyChanged which can be installed as Nuget package (PropertyChanged.Fody). Fody is a series of tools that will inject itself into the Visual Studio build process, modifying the code as it compiles. In this variant, it turns plain auto properties into full INotifyPropertyChanged citizens, including dealing with any dependent calculated properties. Don’t believe me … ? Just fire up the accompanying code for this post from Github and see for yourself. There’s literally nothing more to do other than have your Model classes descend from an INotifyPropertyChanged implementation, and add the PropertyChanged.Fody nuget package to your Model library.

That’s it for the Model layer for now, in my next post I’ll begin my look at refactoring the ViewModel layer.

Don’t forget that all of the code samples for this blog are available on Github, along with my own personal C# / WPF library.

Leave a Reply

Your email address will not be published. Required fields are marked *