MVVM – Bringing it all Together
Great things are done by a series of small things brought together.
Vincent Van Gogh
Having introduced a number of different MVVM / WPF concepts over this blog series, it’s time to bring everything together into one coherent and cleanly structured application.
I’ve changed the layout of the StaffManager demo application substantially from the previous versions. As the data structure is hierarchical (people within departments), it makes sense to reflect that in the user interface – using a TreeView rather than a linear list in a data grid. The left hand half of the main screen holds the full collection of item data, loaded from the data service as required using the Lazy Loading methodology. The TreeView display is built up using a different data template for each ViewModel type.
There is also a person search function – as you type into the text box, the application will search through the full list of people models (not all corresponding people view models are guaranteed to have been created). The two buttons will cycle through the set of matches. Alexey Potapov’s Greyable Image class provides the ImageGreyer.IsGreyable attached property, which will create an alternative image based on the colours of the original bitmap, to indicate a disabled state. I’ll cover an alternative way to handle images for disabled buttons in a future post.
The other half of the screen holds a ContentControl, the DataContext of which is bound to the selected item from the TreeView – a wrapper ViewModel instance. As with the TreeView, there are a set of data templates to control the display. The presenter classes that make up these templates will also be used for the editing screen, providing a consistent layout throughout the application. perControlHost has been updated – allowing an option to display a text string rather than the hosted control. This is used for the non-editing mode of each presenter.
Note the way that the SelectedItem can be set indirectly from any presenter / ViewModel, using the perMessengerService. As with perIoC, this is just a facade over the chosen implementation (in this case another utility from MVVMLight – the Messenger class), providing a single point of reference. This messenger acts like a decoupled event handler – messages of a specific type can be globally broadcast within an application, and will be acted upon by all registered receivers of that type.
So far as editing is concerned, I like to have my applications operate in as clear a manner is possible. I’ve seen applications where multiple levels of edit screens can be opened one after another – children of children being created or updated. After some of these have been closed and perhaps just the first level edit dialog remains, the user is still faced with a window with save & cancel buttons on it – and it’s totally ambiguous just how much (if any) will be undone if they click cancel. I prefer the alternative approach – only one item can be edited at a time, and it’s very obvious what save and cancel relate to.
In the StaffManager application, editing functionality is handled in a completely generic manner by the injected IStaffManagerNavigationService instance. EditModel() can take any object that descends from smModelBase. The parameter is Dynamic type rather than smModelBase, to force the generic methods to use the actual type of the item passed.
Inside MainViewModel.OnEditSelectedItem() the model item to be edited is cloned, and passed to EditModel(). There it is assigned to a fresh ViewModel instance of the appropriate type (with IsEditing set to true), which is sent to the edit dialog. The data template used provides the required controls, and handles validation. If the edit is approved (the user clicks ok) then the cloned Model is assigned back to the original instance. and its ViewModel is refreshed by calling OnModelSet(). The same methodology is used to handle adding a new model object – this is detected by the Id being 0. Note how the IsDirty / IsValid flags on the ViewModel are used to determine the state and behaviour of the save & cancel commands.
I believe that I’ve covered every possible editing scenario – people moving from one department to another, changing their IsManager value, and keeping any checked state. If you find a case that doesn’t work as expected, please post a comment below.
Remember that the purpose of this demo application is to demonstrate usage of the MVVM design pattern. A lot of the coding structures might seem like overkill for such a simple application, but will become more useful as the application grows in size and complexity.
As usual the code samples for this blog are available on Github, along with my own personal C# / WPF library.
If you find this article useful, or you have any other feedback, please leave a comment below.