The Fat-Getter and other MVVM Anti-Patterns
I had to learn one very, very important thing about the software development business: green-field skills are far less valuable than brown-field skills. In the green field there are a finite number of ways to build a software solution “correctly” (according to widely accepted patterns and practices). However, in the brown field, there are an infinite number of ways of build incorrectly—it follows that brown-field skills center upon the ability to quickly see into the infinite and develop a strategy to undo what was incorrectly done and still add new enhancements to the solution. I do not have this talent. The best I can do is write down a few scraps dragged out of the bottomless pit gaping in the shadows of XAML-based, MVVM design.
The Fat-Getter in View Model Properties
Do trust the XAML binding subsystem to display the pre-calculated contents of your encapsulated fields. Do not unintentionally expect the XAML binding subsystem to call a long-running operation in your code.
By convention, the MVVM pattern expects us to bind to the public properties of a View Model. A Property has a getter and a setter. A ‘fat getter’ is one that calls a long-running operation:
public long MyNumericProperty { get { this._myNumericProperty = this.MyLongRunningOperation(); return this._myNumericProperty; } set { throw new NotImplementedException(); } }
When we bind to MyNumericProperty
in XAML, a call to MyLongRunningOperation()
will execute every time the binding subsystem decides to read from MyNumericProperty
. This sort business going on in a grid with hundreds of rows can bring an application to its knees!
Calls to RaisePropertyChanged()Leaking out of Setters
In our terrifying code sample above we can see that MyNumericProperty
has a fat getter and essentially no setter. When a programmer new to (or unconcerned with) MVVM runs into this corner, he can get out of this mess by calling RaisePropertyChanged("MyNumericProperty")
throughout the View Model, outside of the definition of the Property. In my opinion, this effectively makes the mess worse: Do not unintentionally expect the XAML binding subsystem to call a long-running operation in your code.
My years of experience with building XAML applications saw no need for calling RaisePropertyChanged()
outside of its setter. This means that my bind-able properties always look like this:
public long MyNumericProperty
{
get { return this._myNumericProperty; }
set
{
this._myNumericProperty = value;
base.RaisePropertyChanged("MyNumericProperty")
}
}
This implies that in order to call RaisePropertyChanged("MyNumericProperty")
I have to set its corresponding property explicitly. It also follows that any calls to MyLongRunningOperation()
have to be clearly defined in the right space (and time) in the View Model. These self-imposed constraints demand that RaisePropertyChanged("MyNumericProperty")
be called only once but we may see lines like the following several times:
this.MyNumericProperty = this.MyLongRunningOperation();
These lines are placed in the following View Model locations:
- In the
base.PropertyChanged
handler defined in a base, MVVM View Model. This is effectively updating a property based on the change of another property. - In a handler for an aggregated event (Prism) or messenger (MVVM Light).
- In a commanding handler, implementing
ICommand
. - In a handler for a
DomainDataSource.SubmittedChanges
event (RIA Services). - In an element handler for an observable sequence (
IObservable<T>.Subscribe<T>()
).
Knowing where (and when) to update data is both a science and an art. It is quite tragic when anti-patterns prevent such glorious exploration.
No Discipline around Using a Base View Model Class
Notice how I fully-qualified the OOP inheritance of members base.RaisePropertyChanged
and base.PropertyChanged
. This denotes that there is a base View Model class used by all domain-specific View Models in the application. This also strongly suggests that this base View Model in concerned with implementing INotifyPropertyChanged
. What I am writing here seems obvious to any student of MVVM, learning from the classic 2009 MSDNarticle by Josh Smith. But, for those who are new to (or unconcerned with) MVVM, this use of a single base class explicitly concerned with MVVM may seem strange. We get such a base class for free in frameworks like MVVM Light and Prism.
No Discipline around Centralizing/Grouping View Model Logic into Extension Methods
One advantage of using a base View Model is the development of an entry point through which the Open/closed Principle—coupled with the DRY principle—can be intentionally expressed. When a programmer becomes a master of deadlines often the DRY principle is sacrificed and we see the same code repeated again and again across View Models through the magic of copy-and-paste (sadly, working with XAML views kind of encourages this). Using extension methods for a base View Model discourages such a violent thrust into the realm of difficult to maintain code.
In addition to using extension methods for a base View Model, here are some other sources:
- Extension methods for
DependencyObject
and/orFrameworkElement
can be used to centralize event-aggregation or messaging-related procedures—it can keep View-level code ‘clean’ with regard to the particular intra-application messaging system in use. - Extension methods for
Client.Entity
andComplexObject
(RIA services). - Extension methods for
object
is a catch-all for domain-specific procedures.
Overuse of Event Aggregation and/or Messaging
My very short 4/2013 article “Inter-View-Model Communication” was a self-critique about my overuse of MVVM Light messaging (which leads to some alternative extension methods exploiting Microsoft.Practices.ServiceLocation.ServiceLocator
). In the world of Prism, I suspect the overuse of event aggregation when I see ‘too many’ event “payload” data types. This is of course a matter of opinion and, as Steve Jobs said, “Taste.”
Failing to Design View Model Classes to be Partial Classes
The ‘failure’ to design View Model classes to be partial classes is also a matter of taste. Whenever I work with an MVVM-based project I intend to confine my View Models to these concerns:
- Commanding
- Eventing
- Messaging
- Timing (simple animations/timings using
DispatcherTimer
) - XAML Binding (with public, View-Model properties)
- Design-time XAML Binding
For the sake of maintainability, each of these concerns can become a partial class of the View Model. When I see a View Model class definition file exceeding 500 lines of code, I see an opportunity to reorganize the class into its concerns and use partial classes.
Eagerly Disregarding Design-Time Concerns
Sadly, it is very, very easy to find seasoned XAML developers that proudly don’t give a damn about the design-time presentation of their work in Visual Studio. Two comments around this pop out to me, “We don’t use Expression Blend…” and “I write my XAML by hand so I don’t need to see a visual layout.” The first comment is admission of poverty and limited vision (usually wrapped in airs of frugal humility). The second comment is saying, “I press Ctrl-F5 and wait at least three seconds to see the visual design of my XAML—sometimes I do this over 100 times a day. That’s only five minutes of lost productivity for me.”
What that last comment reveals is a lack of concern for others working with the XAML apart from the original developer of the XAML. No matter how experienced a second (or third) developer is with writing XAML by hand, it will be difficult to quickly see what needs to be modified in any XAML layout of reasonable complexity.
Code Is Not Testable
One of the foundational reasons to use MVVM is to have testable code. No “clean separation” between the Model and the View Model is one surefire way to make UI code not testable. There is no MVVM-specific technique that guarantees testable code. Having testable code is a general “design pattern” topic that is beyond the scope of my MVVM anti-patterns. Whenever I see a XAML project that has no unit tests whatsoever, I cringe and wait for the inevitable pig-farm slop to fall on me! In the very least there should be data access/manipulation tests…
Related Resources
“Binding objects to the UI is a large and tedious task. You must implement | |
“If you want to write a testable application, it really helps to plan ahead. You’ll want to design your application’s architecture so it’s conducive to unit testing. Static methods, sealed classes, database access, and Web service calls all can make your app difficult or impossible to unit test.” | |
“Maximizing the Visual Designer’s Usage with Design-Time Data” |
“The design-time |
“Because MEF is being used to import the view models (parts), parameters (such as context) cannot be passed. If you need to pass state for an object that will be created by MEF, you need to set the value for the current state for the type of the context object.” | |
“Watch the author, Mike Hadlow, giving a demo of EasyNetQ at QCon London. And listen to Mike talking about EasyNetQ on Dot Net Rocks.” | |
This design by Gabriel Perez should work better than a similar control I built in 2012 because is features | |
“In MVVMLight | |
“We wanted to have more or less the same execution, but with MEF pulling the strings. We wanted to be able to set the DataContext of a View in its XAML so Resharper can resolve it and give you IntelliSense to the associated ViewModel in XAML which is really handy. We were also quite keen to try and get rid of the ServiceLocater class if possible, which is basically continually growing boiler plate code.” | |
“[Asynchronous] MVVM… Stop the Dreaded Dead GUI Problem in WPF7” |
I’m pretty sure this article was written before |
I did have a issues with MVVM Light moving from SL4 to SL5. | |
“The solution presented in this article uses the right click event handler exposed in the silverlight 4 version and will not work in the previous versions of the silverlight. The solution is to add an event handler to the mouse right button down event in the application startup method.In the event handler we set the ishandled property to true.This essentially prevents the event from bubbling up all the way to the silverlight plugin.” | |
“WPF Validation with Attributes and IDataErrorInfo interface in MVVM” |
“WPF provides validation infrastructure for binding scenarios through |
I thought this was of interest in 2011. | |
Another 2011 thing of interest. | |
“The default | |
This thread shows a sample that uses | |
“Turns out, though, that WPF folks have been using this for YEARS. Here’s Beth Massi talking about CollectionViewSource in 2008, for crying out loud (as I discover it a half-decade later on the phone.)” | |
“Deferring ListCollectionView filter updates for a responsive UI” |
“The solution presented here is to defer updates to the |