I am going through some MVVM articles, primarily this and this.
My specific question is: How do I communicate Model changes from the Model to the ViewModel?<
Your choices:
As I see it, INotifyPropertyChanged
is a fundamental part of .Net. i.e. its in System.dll
. Implementing it in your "Model" is akin to implementing an event structure.
If you want pure POCO, then you effectively have to manipulate your objects via proxies/services and then your ViewModel is notified of changes by listening to the proxy.
Personally I just loosely implement INotifyPropertyChanged and then use FODY to do the dirty work for me. It looks and feels POCO.
An example (using FODY to IL Weave the PropertyChanged raisers):
public class NearlyPOCO: INotifyPropertyChanged
{
public string ValueA {get;set;}
public string ValueB {get;set;}
public event PropertyChangedEventHandler PropertyChanged;
}
then you can have your ViewModel listen to PropertyChanged for any changes; or property specific changes.
The beauty of the INotifyPropertyChanged route, is you chain it up with an Extended ObservableCollection. So you dump your near poco objects into a collection, and listen to the collection... if anything changes, anywhere, you learn about it.
I'll be honest, this could join the "Why wasn't INotifyPropertyChanged autmatically handled by the compiler" discussion, which devolves to: Every object in c# should have the facility to notify if any part of it was changed; i.e. implement INotifyPropertyChanged by default. But it doesn't and the best route, that requires the least amount of effort, is to use IL Weaving (specifically FODY).
Notification based on INotifyPropertyChanged and INotifyCollectionChanged is exactly what you need. To simplify your life with subscription to property changes, compile-time validation of property name, avoiding memory leaks, I would advice you to use PropertyObserver from Josh Smith's MVVM Foundation. As this project is open source, you can add just that class to your project from sources.
To understand, how to use PropertyObserver read this article.
Also, have a look deeper at Reactive Extensions (Rx). You can expose IObserver<T> from your model and subscribe to it in view model.
I have been advocating the directional Model -> View Model -> View flow of changes for a long time now, as you can see in the Flow of Changes section of my MVVM article from 2008. This requires implementing INotifyPropertyChanged
on the model. As far as I can tell, it's since become common practice.
Because you mentioned Josh Smith, take a look at his PropertyChanged class. It's a helper class for subscribing to the model's INotifyPropertyChanged.PropertyChanged
event.
You can actually take this approach much further, as I have recenty by creating my PropertiesUpdater class. Properties on the view-model are computed as complex expressions that include one or more properties on the model.
There's nothing wrong to implement INotifyPropertyChanged inside Model and listen to it inside ViewModel. In fact you can even dot into model's property right in XAML : {Binding Model.ModelProperty}
As for dependent / calculated read-only properties, by far I haven't seen anything better and simpler than this: https://github.com/StephenCleary/CalculatedProperties. It's very simple but incredibly useful, it's really "Excel formulas for MVVM" - just works same way as Excel propagating changes to formula cells without extra effort from your side.
You can raise events from the model, which the viewmodel would need to subscribe to.
For example, I recently worked on a project for which I had to generate a treeview (naturally, the model had a hierarchical nature to it). In the model I had an observablecollection called ChildElements
.
In the viewmodel, I had stored a reference to the object in the model, and subscribed to the CollectionChanged
event of the observablecollection, like so: ModelObject.ChildElements.CollectionChanged += new CollectionChangedEventHandler(insert function reference here)
...
Then your viewmodel gets automatically notified once a change happens in the model. You can follow the same concept using PropertyChanged
, but you will need to explicitly raise property change events from your model for that to work.