Note: This is part of a series, you can find the related posts here…
Displaying and manipulating data on the client – the one and only purpose of any LOB application – includes two things if it comes to Silverlight: a) The asynchronous server calls and b) the client architecture. I will be going over them in a cursory fashion and come back later to address each one in more depth. This time the client architecture.
View Model basics
The client code is largely guided by the employment of the Model-View-ViewModel (M-V-VM, or MVVM) approach, which is the predominant architectural approach used with SL and WPF. The reason probably being that it is a natural counterpart to the WPF and Silverlight data binding features, the two work extremely well together.
Cook book style:
- For every page (the view) there is a respective class (the view model) that manages the data (the model).
- For each control on the view that shall be populated dynamically with data, the view model has a corresponding property providing the model.
- For each control state, such as enabled or visible, that shall be controlled by the logic, the view model has a corresponding property, probably boolean.
- For each action triggered by the UI the view model has a respective method.
The view model is very closely associated with its view, so there is not much reuse here, but then, it largely consists of properties and forwards to service calls. Or so the theory says. (Subsequent posts will gave deal with the shortcomings….)
Please note that it is debatable whether the data provided by the view model actually is the model. Another approach would be to expose a view related data model, namely view entities. The view model would have to map them to the data model (the model) the lower layer exposes, probably some service proxy.
Both approaches have pros and cons, however you’ll mostly see the former approach, since it’s well supported by the tools (service proxy generation, etc.). Still, it has some cons…
Anyway, the only technical demand for view models in SL is due to the intended use for data binding: Classes subject to fully fledged data binding need to support the INotifyPropertyChanged interface for simple properties, while collections have to support INotifyCollectionChanged. The later one comes for free if you use ObservableCollection<T> consequently. (Please note that data binding works with conventional properties, but only to a limited degree.)
For INotifyPropertyChanged a little base class comes in handy:
Note the generic overload. That’s a little trick to avoid typos in the property name argument.
With this class as base a property implementation usually follows this idiom:
(Without that trick one would have to pass the property name as string. A source of errors due to typos, and a pitfall during refactoring.)
BookFilter is a data class that, again, follows the same pattern, i.e. it supports INotifyPropertyChanged.
Hint: This begs for a code snippet! 🙂
The View Model
Any book shelf has a collection of books, so does my application. The book list page should provide a means to filter the book list (two text boxes), a button to trigger the search, and to show the result (a data grid):
Not especially nice and the grid is a little degenerated for now, but that will change. In XAML:
Thus the first view model implementation may look like this (including some simple test data, the next post will deal with the server call):
Databinding
For the actual binding I need to wire that up with the page. The usually presented manual way looks like this:
The view model class is created in the c’tor, and assigned to the DataContext. A property provides a more convenient access to it. This is already used in the button event handler that triggers the book search.
However, I recommend against this way. Rather I did the data binding in Blend…
Opening the page, selecting the first textbox, finding the Text property in the properties and clicking the text box (or that tiny little dot to the right) brings up the context menu.
Then I choose data binding, the Data Field tab, and the +CLR Object button:
That left finding the view model class and selecting it:
This way I could add various “data sources”, yet I only want one for now, and according to M-V-VM, for ever. Afterwards the dialog lets me browse the class structure and select the property to bind against:
On second thought, I selected the StackPanel which contains the filter textboxes and bound it against the BookFilter property, in order to narrow the available context. Afterwards the textboxes could be bound via the Explicit Data Context tab:
I had to expand the lower area to set the binding to TwoWay.
But I didn’t have to go through the dialog armada for every field. Blend also provides the data tab that lets me browse through the available data sources. Drag’n’drop of field simply works and generally uses the last settings from the dialog, i.e. it includes the TwoWay setting. Also it binds by against the default property, but if I hold the shift key down it lets me choose the property. And some other stuff I leave to you to explore. Really nice.
Anyway, this is what Blend just created for us in markup speak (just the relevant part):
It registered the namespace to locate the view model class, created the view model as resource, set the DataContext of the LayoutRoot element to this resource, and it added the usual binding to the subsequent controls.
Changing the generated prefix to viewModel was all I did. Otherwise I could live very well with that, given that is achieves all I need and it allows me to do my data binding much more efficient and less error prone in Blend. The manual way was opaque to Blend, thus it couldn’t assist me in any way.
The only thing left was removing the manual instantiation from the c’tor and changing the ViewModel property to use the LayoutRoot control. I may have moved the binding to the page instead, but I prefer to work with the tools, not against them.
After running the application and clicking on the button, it shows the respective test data:
The next post will deal with the actual server call.
That’s all for now folks,
AJ.NET
Hi!
I liked your intro to MVVM, but I do think you are coupling your VM to the view by handling the buttons click event in the code behind and having a reference to the VM in the code. By adding ICommands and a commanding architecture you get better decoupling.
If I decided down the line to switch the view, which happens, and I was using your way, I would have to redo the layout as well as rewrite all of the interactivity and eventhandlers. If you let the vm implement ICommands instead and use a commanding architecture, you leave everything up to the vm and can switch the view completely without any code changes at all. The less the different parts know about eachother, the better. Bindings do not need to know what they are binding to, so they allow you to switch the VM without any problem. By binding your functionality you decouple everything more and open up the solution to change…
But that’s just me…
Cheers,
Chris
Comment by Chris — February 2, 2010 @ 12:56 am
Thanks for the feedback. And I fully agree with your opinion.
Actually I do have an ICommand implementation. I didn’t mention it in this post, because I wanted to focus on one aspect at a time since these Silverlight posts are meant as introductions (the post got long enough anyway).
The reason I haven’t written about it since then is simple and twofold:
1. I’ve stumbled over several other references (I haven’t really checked them in detail, though), which led me to think that I cannot contribute something new.
2. SL4 is just arround the corner and by then, half of the work would probably be redundant.
Anyway, these reasons so far have kept me from even considering a blog post about this. Still, if anybody wants to read about ICommand trigger and handler, just drop a comment.
Comment by ajdotnet — February 3, 2010 @ 8:39 pm
Well…SL4 is around the corner, but the command support in that release is somewhat limited. The Command property is only available on ButtonBase classes (I think), and thus is kind of limiting… This is the way that most command managers do it, but that means that you for example can’t get a command to execute when a drop down is changed or other usefull scenarios. Since triggers aren’t available in SL, I’ve seen a few implementations using Behaviors or Actions. The problem with those is generally that you can’t bind your values to them as they don’t inherit from FrameworkElement. This will probably be changed in v4 when bindings are limited to DependencyObject instead of FrameworkElement…
Cheers
Comment by Chris — February 3, 2010 @ 9:44 pm