I strongly suggest that you implement INotifyPropertyChanged on any class that will be a binding source. I’ve been doing some memory profiling recently and ran into a HashTable outside of my code that was holding on to a reference to one of my view models. Here is Microsoft’s listing on the leak.
The basic idea is that when the source of a binding is a(non-Dependency) property on a class that does not implement INotifyPropertyChanged, WPF creates a ReflectPropertyDescriptor to facilitate the binding. The Microsoft page seems to suggest that this should allow for updating the binding value when the backing property changes, but this doesn’t actually work. The ReflectPropertyDescriptor gets added to a global table and does not get removed, creating a memory leak.
At first glance, it looks like your view model needs to have a reference to the View because of the second condition:
Object X contains a direct reference or an indirect reference to the target of the data-binding operation.
Later there is a note that says that the binding can cause this “indirect reference” to the view:
The reference between object X and the data-binding target is caused by the first condition that is listed in the "Cause" section.
I have created a simple test bed application that shows the problem. Setting a break point in the Finalizer of ViewModelOne shows the memory leak. When INotifyPropertyChanged is not implemented, the Finalizer never gets called. Adding the implementation of INotifyPropertyChanged allows the Finalizer to get called.
The take-away? Make sure you implement INotifyPropertyChanged on view models. Microsoft calls this behavior “by design”. It sounds an awful lot like a bug to me.