ViewModel Pattern for Silverlight - Options for Hooking a View to its Model

There are multiple ways to associate a View to its Model - for example, using a ViewModelLocator, or perhaps a convention-based approach I am thinking of implementing. What are your thoughts and opinions? I'm looking for feedback to improve Silverlight.FX, and potentially make suggestions to Blend/Cider teams for future ViewModel support...

In the ViewModel, aka the MVVM pattern, a view such as a UserControl is bound to its associated view model. The view model manages state exposed as observable properties, operations exposed as methods and raises notifications via events. An interesting question is how a View should specify its view model, and how a view model instance should be created. Like everything else in the ViewModel pattern, this topic is no different. There are different strategies, with pros and cons, and different people have different opinions.

In this post, I'll describe a couple of options, and hope to collect some feedback as well as ideas on alternatives. Part of my goal here is to improve what is supported in Silverlight.FX out-of-the-box. The other goal is to find what resonates, and see if I can collect input on suggestions I'd like to make for future ViewModel support in Blend/Cider - so any thoughts you share will certainly help. Looking forward to hearing them...

My general criteria for evaluating each approach is the following:

  1. It should be possible to create the view model through an IoC container, so its dependencies (properties, or constructor arguments) should be satisfiable. In other words, its likely a view model can't be instantiated directly in XAML... at least not in the subset of XAML supported by Silverlight today.
  2. The mechanism should not interfere with designability either in Blend.
  3. Furthermore, the mechanism should even lend itself to designability. For example, the data-binding picker should allow binding to properties on the view model.


Current/Default Silverlight.FX Approach

Silverlight.FX offers classes such as Form, Window, Page and ViewUserControl that derive from a View base class that in turn derives from UserControl. The View class exposes a ModelType property, and uses the application-scoped IoC container to create an instance of the view model, so that any dependencies of the view model can be satisfied during instantiation. It sets the resulting model as the DataContext, and it also sets it as the Model associated with the View.

The markup looks something like this:

<fxnav:Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:fxnav="clr-namespace:SilverlightFX.UserInterface.Navigation;assembly=SilverlightFX"
  xmlns:views="NewsWidget.Views.News"
  ModelType="NewsWidget.Views.News.ListPageModel"
  d:DataContext={d:DesignInstance Type=views:ListPageModel}">
</fxnav:Page>

This satisfies criteria #1 in wish-list where the View has a type and it can control when and how to create the view model instance.

However it doesn't lend itself well to criteria #2. Blend doesn't like this syntax. At design-time, the Blend parser wants a valid Type for the ModelType property. However at runtime, Silverlight doesn't support properties of type System.Type... well not yet. I did create a user voice item here - go vote for that if you care about being able to declare properties of type Type in XAML.

To satisfy criteria #3, i.e. the binding picker, d:DataContext needs to be set in addition (as shown), which is unfortunate duplication.

Other options are available in Silverlight.FX, but this is what I've been using by default in my samples. I am looking to improve it which brings me to two alternatives: ViewModelLocator and a ViewModel-via-Convention as described below


Quick aside on DataContext and Model

Having the notion of Model as introduced by the View base class in addition to standard DataContext is very useful. Silverlight.FX implements this, but I haven't seen other view model frameworks implement something similar. Having a concrete notion of Model allows any control in the view to access the view model even if it has a different DataContext. Imagine individual items in an ItemsControl - each has a different DataContext, but still share the same Model, which allows invoking methods on the view model from say a Button within the item. Example: You have a list of products, and the template for a product contains a Buy button, that when clicked, you want to call into the Buy method of the view model passing in the product.


ViewModel Locator

Arguably this is the most prevalent approach out there today. The idea is reasonably straightforward. You write an actual class called the ViewModelLocator, which exposes the different view models in your application as properties. Your implementation of the property getter now controls how to create the view model, for example, by invoking the IoC container, using MEF, or any other mechanism, and you have full control. Next you declare an instance of this locator in your application's resources, and then bind your view's DataContext to it.

public class AppViewModelLocator {

    public ListPageModel ListPage {
        get {
            // code to create and return an instance
        }
    }
}

<Application>
  <Application.Resources>
    <app:AppViewModelLocator x:Key="vml" />
  </Application.Resources>
</Application>

<fxnav:Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:fxnav="clr-namespace:SilverlightFX.UserInterface.Navigation;assembly=SilverlightFX"
  DataContext={Binding ListPage, Source={StaticResource vml}, Mode=OneTime}">
</fxnav:Page>

Pros:

  • It allows full control over creation of the view model instance.
  • It keeps the designer happy, and binding pickers also work as expected.

Cons:

  • It requires me to write an AppViewModelLocator class and furthermore, each time a new view model is added to the project, the locator class needs to be updated.
  • Views now depend on the key assigned to the ViewModelLocator resource. This works in small applications, but introduces less than ideal string name interdependencies when you have views spread across projects in a larger application.


Convention, rather than Configuration

In all my app-building I've noticed I end up having 1:1 correspondence between my View and its associated ViewModel. Yes, this isn't necessarily true in general with the ViewModel pattern, but I've also found the best way to explain the ViewModel pattern to those new to it are to explain it as a refactoring of code-behind into a separate class that isn't coupled to UI concepts. As such it becomes 1:1. What is more, I've also been using a naming convention. If I have a view called FooPage, then I have a corresponding view model called FooPageModel.

If I have that convention baked in into the View base class in Silverlight.FX, I would not need to specify the Model explicitly. This would be all the markup I need:

<fxnav:Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:fxnav="clr-namespace:SilverlightFX.UserInterface.Navigation;assembly=SilverlightFX">
</fxnav:Page>

Much simpler!

Pros:

  • Still allows control over creation of the view model instance by letting the View create one via a container.
  • Blend is happy.
  • Doesn't require me to write a ViewModelLocator class.

Cons:

  • I still have to specify d:DataContext to get the binding pickers to work. This is not a non-starter however, as the designer might very well be using sample design-time data rather than the view model itself at design-time. I still do wish the designer would also understand and honor this convention, and automatically infer a design-time DataContext if nothing is specified. My hope is to convince the Cider and Blend folks on thinking about this approach. What are your thoughts on a convention-based approach like this one? Should I pursue and run this by the designer teams?


Time for Your Opinions

Given both alternatives aren't without some cons, which do you think is preferable? If I optimize for the simple case today, the ViewModelLocator is slightly better. If I optimize for larger scenarios, and look forward optimistically, the convention-based approach seems like the better long term approach.

Or do you have your own approach or some variant of the above that you'd like to share for consideration?

Posted on Friday, 12/11/2009 @ 9:42 AM | #Silverlight


Comments

31 comments have been posted.

Colin Blair

Posted on 12/11/2009 @ 10:08 AM
In my situation I have a lot of ViewModels that are shared by two different views. This is because my master view and detail view are two seperate views that share the same ViewModel. My approach is that I have an IView<T> and an IViewModel<T> interface. I actually further derive that down to IGridView<T> and IEditView<T>. The reason for this is that I am using a docking metaphor for my UI. The master views are document windows in the middle of the screen and the detail views are like the property window in Visual Studio.

The "by convention" idea would work great for me as long as the convention can handle multiple views. So, for example, if FooViewModel maps to any view that ends in Foo then I could have GridFoo and DetailFoo.

Anderson Imes

Posted on 12/11/2009 @ 10:12 AM
I really like the convention approach. Generally I put my ViewModels in a different namespace though, but they are named very much like your example. If we could possibly modify the convention (by providing a new mapper in the App.config, for example) I'm sold!

Nikhil Kothari

Posted on 12/11/2009 @ 10:19 AM
I've gotten feedback about making the convention definable by the app developer - I haven't seen a great way to do it in config. I'd love to think about it however ... got any ideas for specifying the convention declaratively in App.xaml?

wekempf

Posted on 12/11/2009 @ 10:46 AM
Interesting article. A few comments.

Onyx (http://wpfonyx.codeplex.com) differentiates the ViewModel from the DataContext, but does so without using a base class. Instead, it uses an attached property with some property changed and value coercion magic. It satisfies (1), while being instantiated directly in XAML and is supported by Silverlight today. It also, I believe, satisfies (2) and (3), though there's room for improvement.

There's a more fundemental design question/decision you've not addressed, however. All of your solutions are "View first", but "ViewModel first" is a very valid, and often necessary, alternative. I'm working on Onyx to make it support both, in a fashion that's Blend/designer friendly. I'm also trying to work out how to do this both by "convention" and by "configuration". I'm not there yet, but what exists today might still be worth your taking a look for inspiration in your own endeavors.

Rob

Posted on 12/11/2009 @ 11:22 AM
As you can see from http://caliburn.codeplex.com/wikipage?title=View%20Strategies&referringTitle=Documentation and http://caliburn.codeplex.com/wikipage?title=IBinder%20and%20Convention%20over%20Configuration&referringTitle=Documentation we have been using conventions for quite some time. The mechanism is fully extensible and customizable by the developer. You may be surprised just how complicated it is to pull this off in real applications where you have to support multiple views over the same model, multiple models against the same view, different forms of application organization, composite View Models, etc. Furthermore, once you add conventions, you need a mechanism where by you can report on what conventions are in effect within a given context because while conventions are a huge boon to productivity they can create very difficult to find bugs. So, don't take implementing a feature like this lightly. If the WPF/SL team were to include something like this, what I would really want is a way to have it call into my framework. Most of all, I don't want to have to jump through even more hoops to get my code to play with VS/Blend.

Laurent Bugnion

Posted on 12/11/2009 @ 11:30 AM
Hi Nikhil,

I am also exploring various options for the MVVM Light Toolkit. Currently I am leaning towards a ViewModelLocator based approach (like now) but with a different way to register and resolve ViewModels, a little more similar to what IoC containers do. I also consider resolving the ViewModels based on the View's type (there are multiple ways to get an access to that information). However I did not settle on a final implementation yet.

I want to mention that having a "middle man" (the ViewModelLocator) has some advantages too. Having a centralized class handling the VM's lifetime offers, in my opinion, big advantages in certain scenarios. I like to offer a way to instantiate a VM at a known time, with certain parameters. Another advantage of the ViewModelLocator is that it lends itself very well to mixing an IoC container (NInject, Unity...) and MVVM. I know a few people who resolve VMs with Unity in Silverlight, for example, and who use the VML as a Service Locator. This works great. Also, wiring the VML and all the VMs can be done in Blend, for example in an existing application that must be converted to an MVVM approach, which avoid typing XAML code (in the opposite, Blend does not allow to specify attached behaviors with an editor, so you need to type some XAML code. Not a huge deal, I agree, but still).

Finally, the last argument in favor of the VML in my opinion is that it is easier for beginners to understand what happens. As powerful as d:DataContext is, it is a bit of magic. Same can be said about attached behaviors, it is not immdediately clear exactly what happens under the covers. On the other hand, the creation of a VM in the VML is easy to understand, for example which constructor is chosen depending on which parameter.

As I said, I am not totally decided yet which approach I will use in a next version of the MVVM Light Toolkit (V4 probably), but I thought it would be interesting to mention these points based on my experience and my users' feedback for the past year or so.

Cheers,
Laurent

Rob

Posted on 12/11/2009 @ 12:15 PM
What if you supported a design time call back, like the query IsInDesignMode attached property, but something we register a handler for. Then whenever the designer is trying to figure out what the context for a view is, it can hand us the view instance and we can hand it back the appropriate data context. The attached property d:DataContext could also use this mechanism under the covers. Now, I'm not sure how I would actually have an opportunity to register a global handler for my app with VS/Blend, but I think it would be interesting to think about. Then each framework could supply it's own handler to the designer.

Rob

Posted on 12/11/2009 @ 12:19 PM
Ok. Solution is simple. Create a new attached property that can be added in the App.xaml. This property would register an instance of a class which would receive a view instance and return a view model instance. VS/Blend will use this attached property to wire into its vm resolution logic and will call the implementation each time it needs design time data. Thoughts?

Laurent Bugnion

Posted on 12/11/2009 @ 12:41 PM
Rob, what you are proposing is a ViewModelLocator (gets a View and returns a ViewModel) hooked via an attached behavior. It works (Jaime Rodriguez uses that to create his VMs) but I don't like this because attached behaviors are not as Blend friendly as hooking the VML through the resources.

Rob

Posted on 12/11/2009 @ 1:29 PM
What I am proposing is some mechanism that we can use to let blend call into my application code so that I can tell it what the View Model is based on an arbitrary set of rules. Design time attached behavior was the first thing that came to mind. Personally, I have no desire to use this at runtime (I use a VM first approach), but I want a way to tell blend, given View X, use ViewModel Y for the data context. And I want a way to set this at the application level, so that I don't have to tell it for each view.

András Velvárt

Posted on 12/11/2009 @ 1:39 PM
What I prefer is an "Application View Model" - kind of like the ViewModel Locator sample, but it is the actual Datacontext of the main form. Simple, Blendable, natural (models the entire application using its collections, properties and states), allows for configuration, and no need for d:DataContext. Subsequent viewmodels get created as properties accessed or as the collections get filled. Haven't used this on huge projects though.

Shannon Cornish

Posted on 12/11/2009 @ 2:17 PM
What I've done in my applications is to create a new DataProvider class (inherit from ObjectDataProvider) that allows me to set the data property (or when in design mode, will create the ViewModel itself).

I've then added this to the view using Blend and set the DataType of the provider to be a ViewModel type. (ViewModels take in no dependencies so can be created easily).

I then create a controller class that exposes the ViewModel, the controller is responsible for the logic and talking to services etc.
I've got an attached property on the Window that links the controller to the view model provider.

I've been calling this pattern MVCVM because of the introduction of the Controller classes.
I've been finding it quite nice and has very good testability, allows reuse of the view models and separates out the responsibilities of the view model.

Because view models are really only state and property change notifications, the designer can handle them create and this pattern has create testability and design ability (requirements 2 and 3).
<w:Controller.Host Type="{x:Type IMyWindowController}">
<ViewModelBinding DataProvider="myDataProviderInWindowResources" DataMember="NameOfViewModelPropertyOnController" />
</w:Controller.Host>

When the host type is set, it gets the instance of the controller (which is populated with services and view models) and hooks up the data source to the controller view model property.

Laurent Bugnion

Posted on 12/11/2009 @ 2:52 PM
@Rob Ah OK I understand what you mean. Yes, VM first is harder at design time. Switching to a View first approach at design time sounds like an interesting idea for those VM-first apps. Personally I prefer to stick with View first, but I know quite a few people who differ.

Fallon Massey

Posted on 12/11/2009 @ 5:13 PM
@Laurent - I think that both methods are important. While most times I do View first, sometimes I want to do Model first.

It's equivalent to Entity Framework(or any ORM), sometimes you want to design first, then derive the data model from the design, and sometimes you create the data model, and then it drives the design.

Both ways are equally valid depending on the project.

Sharker Khaleed Mahmud

Posted on 12/11/2009 @ 8:33 PM
Great article. I think Silverlight.FX 3.2 need to be updated as most demos are not working. For eg. the pipe for weather widget is returning this

jsonObject value returning is this {"count":1,"value":{"title":"Weather2","description":"Pipes Output","link":"http:\/\/pipes.yahooapis.com\/pipes\/pipe.info?_id=WrXN95ta3RG3WFMqbrsjiw","pubDate":"Thu, 10 Dec 2009 05:21:17 +0000","generator":"http:\/\/pipes.yahooapis.com\/pipes\/","callback":"","items":[{"err":{"content":"Invalid Partner Code.","type":"100"},"description":"","title":""}]}}

//throwing error here
JsonValue location = jsonObject["value"]["items"][0]["loc"];
JsonValue currentConditions = jsonObject["value"]["items"][0]["cc"];
JsonValue forecastConditions = jsonObject["value"]["items"][0]["dayf"]["day"];

Any quick fix/response appreciated.

Thx
Sharker

Carlos

Posted on 12/12/2009 @ 10:51 AM
I prefer viewmodel first approach as I prefer to abstract the view away from all my code. The view is specified as a type on the view model and unity is used to instantiate it. The view has absolutely no code and has the viewmodel set as its data context, so there are no issues at design time. I have used prism to insert the view into the page and have designed my own navigation that uses prism's composition namespace. See http://u-ix.blogspot.com/.

Nikhil Kothari

Posted on 12/12/2009 @ 1:29 PM
Great comments - thanks for participating in the discussion.

It seems like convention is an interesting choice if there is a way to plug in something that can override the convention with a customized convention. Seems like potentially something at the application-level... perhaps adding an object that implements IViewModelFactory in the IoC container. It gets a view type, and returns a view model type. At the same time I think I'll support explicit setting of the DataContext, and using that as the view model ... so in essense both options can co-exist.

The other thing the comments touched on was an ApplicationModel class... in fact Silverlight.FX has this. And if a View doesn't have a specific view model, the View class just uses the ApplicationModel as its view model.

Yet another thing that came up here was view-first vs. view model-first. I personally prefer view first. I don't want my view model to indicate view type (thats undesirable coupling), and I also don't want to create an external registry mapping view model to views (too much work IMO). However, there are of course folks who prefer that approach and that is fine. I think this is one of those personal choices in the view model space. I think the decision needs to be made on the basis of which has overall more positives factoring in different set of requirements.

Colin

Posted on 12/12/2009 @ 7:43 PM
Hi Nikhil,

I am using 1) & 2) in my project.

In the VM:
DataContext={Binding ListPage, Source={StaticResource vml}, Mode=OneTime}"

Then in the view, I need to set the model for SilverlightFX
this.Model = DataContext;

To be honest this isn't such a big deal to me, as long as it works!

However, one thing I would like to see in Silverlight/SilverlightFX is better error handling, in the case of making a typo on a method name for an action, I get the dreaded Silverlight White Screen Of Death. It can be hard to track down what's wrong, any tips?

Another thing that is currently a pain point, is that I am using your Task pattern. It works fine for your example, but now I have a class with 50-100 properties and I will need to repeat myself a lot for the Copy & Clone methods, and also for DTO to persistence. (Maybe an import method for DTO -> BO also). Now if I add one property to my BO I will need to update in 4 places. Is there a better way?

Thanigainathan

Posted on 12/14/2009 @ 12:31 AM
Hi Nikhil,

I would prefer the convention based approach. But there is one thing which needs to be considered. One view may share more than one data model. So in that case there should be some solution.

Thanks,
Thani

Adam

Posted on 12/14/2009 @ 11:27 AM
I like the convention-based approach as it feels like ASP.NET MVC. Additional support for areas would be nice as well.
What if you had a default convention mapping defined using something like a UriMapper-style control like you have for Silverlight navigation-based apps?

Maybe something like this:

[ns:ViewModelMapper x:Key="viewModelMapper"]
[ns:ViewModelMapping View="/Views/View1" Model="/ViewModels/SharedModel.cs" /]
[ns:ViewModelMapping View="/Views/View2" Model="/ViewModels/SharedModel.cs" /]
[ns:ViewModelMapping View="/Views/{}{view}" Model="/ViewModels/{view}Model.cs" /]
[/ns:ViewModelMapper]

This would handle the simple scenarios by default, but allow explicit overriding either globally or for one-off scenarios.

Maybe this View-to-ViewModel mapper component could live in the main App.xaml file.

Any takers?

Nikhil Kothari

Posted on 12/15/2009 @ 6:14 PM
@Thanigainathan
Given a view has a single DataContext, I'd recommend you build a specific view model that composes multiple underlying data models and expose them as properties on a single view model type.

@Adam
ViewModelMapper sounds interesting... its similar to what I was thinking. Specifically, I'd define IViewModelFactory, and you'd place an instance of a type implementing that within the IoC container (in Silverlight.FX, you can do that simply by placing it App.xaml within the ApplicationContext object). Then different people can implement different strategies based on their needs. One such implementation might use a mapper like you have...

Gaurave Sehgal

Posted on 12/16/2009 @ 7:40 AM
Another way which we are using in WPF, and not sure if it will work with Silverlight. We have created DataTemplate in a resource file where DataType is ViewModel and inside ViewModel invoked view like this.

<DataTemplate DataType="{x:Type viewModel:SearchViewModel}">
<view:SearchView/>
</DataTemplate>

Jonathan

Posted on 12/25/2009 @ 12:15 PM
@Gaurave,

The DataType property wasn't there is SL3.. not sure about 4. It certainly is a nice feature.

Kirill Chilingarashvili

Posted on 12/28/2009 @ 1:24 AM
Hi Nikhil.
I use attributes in code behind of a view to provide type of view model this view is designed to be used with,

This allows me to provide type in a strong-typed way - checking existance of type on compilation stage.

for example:

[Option("TestView", typeof(TestViewModel))]
public partial class TestView ..................


Here metadata attribute Option provides a name "TestView" which may be used to navigate to this view (my app framework can load views by the names provided in metadata).
Also Option attribute says which type have to be initialized and used as view model for this view.

Views and View Models in my framework are instantiated using unity, - therefore constructors of both can have overloads accepting interfaces registered in unity container which is in effect in current scope.

The good with this approach is - the metadata is used on this stage - and changing app framework in future may change the way this information is read from in future- for example in future implementation the views "names" and view model types may be coming from DB or XML files.

Nikhil Kothari

Posted on 1/2/2010 @ 1:15 PM
@Kirill
Thanks for sharing. I agree with you - the attribute is a nice way to override the convention.

By the way, I just implemented and checked in the convention support in Silverlight.FX. It uses either a Model or a ViewModel suffix, and you can override by using a [ViewModel] attribute on your view. If you want to do anything different, then you can set the View.Model attached property. So I think that brings about flexibility and simplicity at the same time.

abhi

Posted on 1/5/2010 @ 4:38 AM
Hi Nikhil,
I have been following you for quite some time now. Your work is amazing. Now that the libraries are growing big, is it possible to extract only those required for the apps? My clients are kind of concerned about the loading time (though they need better features). Is there any tool available for static linking the Silverlight libraries? I remember reading you mentioning about something like that. Is that available?
Thanks
Abhi

Nikhil Kothari

Posted on 1/5/2010 @ 2:02 PM
@abhi
The library is still around 75K compressed without any external dependencies. I've taken care to try and keep it minimal. My mental budget is 100K quota... if I get past that, I will probably factor some things out into separate libraries.

Right now there isn't yet a tool to static link things. I have some ideas, but nothing implemented as of yet.

Atam

Posted on 1/12/2010 @ 7:55 AM
hi Nikhil,

like above, i agree "Your work is amazing".

I got a few questions:

Is SilverlightFX 3.2 compatible with Silverlight 4?

Because wcf ria services support inheritance better, i have to move up to .Net 4 beta with my project.

If not, when is a new release with support for Silverlight 4 to be expected?
Also, when can a release with the functionality as described in this topic be expected?

Thanks again
Atam

Nikhil Kothari

Posted on 1/15/2010 @ 5:46 PM
@Atam
Yes, Silverlight.FX can be used with Silverlight 4. There is one conflict - my use of the Window class name conflicts with what was added in Silverlight 4, so that requires namespace-qualification. However, I've made changes on my end to account for that, and will hopefully publish a new build of Silverlight.FX soon with that change...

Visual C# Kicks

Posted on 2/14/2010 @ 1:29 PM
I prefer the convention approach although like you said, it isn't without it's drawbacks.

Shaun

Posted on 1/25/2012 @ 2:31 PM
Fantastic article. Have you reached any consensus on this design challenge over the past 2 years?
Post your comment and continue the discussion.