M-V-VM training day sample application and decks

During the M-V-VM training (last saturday) with Karl Shifflett I showed and referred often to this Southridge application below..
The app is not very clean(when it comes to resources and styles in particular) but it is a fairly good ViewModel example, and it served well to illustrate a few of the points we made at the training (both good and bad practices).  So I am sharing it (as promised).   

The application consists of three views sharing one ViewModel around real-estate data (called MainViewModel).

The application's chrome includes a ribbon that drives all the Viewmodel via its filtering functionality.  The two filter commands that work are Bathrooms and bedrooms [if you change the selection for these, the results on the views should filter].

image 

I purposedly did not make the main window with the ribbon a view because I often run into applications that transition views so I wanted to show the concept of having a constant element in the chrome.   The ribbon is functional ( you can see its resize behavior).
The checkbox columns are bound to the MainViewModel, and drive the columns that show up in the Search view (below).

The views
Again, the views are the results for the search from the criteria in the ribbon. 

image image

Both of these views are 100% XAML. 

The grid is very functional, sort, selection, etc.   I call it SearchView.
The map is simply a Listbox with a datatemplate and a tooltip on the ListBoxItems. I need to add more to that UI.  I call it the MapView :)
You navigate to the map view, by either clicking on the map icon on the left hand side of any row of the data grid, or by clicking on the Map Ribbon button on the Search Results tab. 
The full details of course include an OpenMap Command exposed in the MainViewModel that does the work.

To go back to SearchView (from any view), just click on the Search tabs, and it automatically goes back.  The way that happens is through an attached behavior in the RibbonTab:

 <r:RibbonTab Name="SearchTab" Label="Search Criteria" view:RibbonTabSelectedBehavior.SelectionChanged="{Binding SearchSelectedCommand}" 

This is a standard attached behavior that delegates the event and 'forwards' it the SearchSelectedCommand on the MainViewModel.  You can see the implementation on the RibbonTabSelectedBehavior class.

There is another totally different View, called Profile.. 

image

This view demonstrates data validation using IDataErrorInfo. It has an InfoTextBox (from Kevin Moore's bag-o-tricks) and shows the fields that are invalid in red.

The validation is trivial, mostly checks for empty strings on all fields, except zipcode, around ZipCode it enforces the 5 digits or 9 digits with a dash format for US Zipcodes.

[For details, check the Profile class] in XMLData project. ]

You can see how the "Save Profile" command is wired to only be enabled when the data is valid.

The Profile view purposedly contains a "PreferencesEditor" usercontrol that is not a view itself; it takes data context and drives its UI from it, but does not have full view functionality (again to illustrate a point: not every thing is a view).

The profile window has both a DataTemplate ( for everything in "Contact information"). 

The listboxes in Location are interesting because they State is populated with read-only data (I call it meta-data) that is not coming from the view model,  but the views are bound to the Viewmodel when selection happens (county is driven by the selection on State).   Be aware that the data is not big and some states (e.g. CA) might not have valid data. Try WA to see it the way I see it.

 

The final screen is the Listing Details screen. This is a modal window that shows Listing details. Nothing too exciting here but it is a wired view model, including the Make appointment button. You may notice that the "Neighborhood" data template in this view is the exact same data template from the Tooltip on the map.   yes, I am lazy and I drive reuse, that is why viewmodel is my friend.

The Listbox has a very "view specific" behavior implemented by 3 lines of code behind, it is used to implement selection when mouse enteimagers a listboxitem. I purposedly left it as is, though I am sure some M-V-VM purist will tell me I should have implemented it as an attached behavior. I chose not to because I did not want the viewmodel to manipulate the view on a quirk like this one. The view can self-contain the behavior and yes, if I try to move the code to Silverlight it will need the same 3 liner. I was OK with that.  I felt it was equally bad to have the ViewModel be listening for view events and "manipulate the view" directly (which I would have needed).

At last, there is one class that keeps it all together, I called it the ViewManager. This is an over-simplistic implementation of a Presenter for the views that handles transitions across the views.  The views register with the viewmanager as they are instantiated, and the ViewModel can trigger call into the ViewManager ( a singleton) of course to trigger transitions across views. The viewManager itself can have a ViewModel if needed; in this case I did not use it, but in other apps I have used it.

That is it, if you were at the class I hope you remember this.  If you were not, then maybe looking at the deck might help, though I must say the class was quite driven by example, so the slides are a bit presentation-zen-like. Please try the notes for a bit more context and drop me a comment or email if that is not cutting it.

At last, thanks to all those that attended the class. It was a lot of fun, and I really enjoyed meeting all of you.

Thanks also to Matthias & Bruno & Karl for puttting it together and for inviting me. 

Presentation (ppt deck) is here.   Code is here.  The code requires the WPF toolkit, all assemblies needed should be included in the project but if you get a compilation error, try getting the toolkit and the ribbon from codeplex

[Disclaimer again, the code needs some heavy scrubbing on the UI and resources; also I had to take out the data that I normally use, so if you see #if SQLCE, simply ignore these.  I replaced all the data with an XML file (for easy tweaking). It is not real data, so don't be surprised when you see a Seatttle address in an Issaquah neighborhood.  I merely invented the data on the fly].