Reasons to not use a ViewModelLocator at design-time

In my last post I wrote about how I had created a ViewModelLocator that was a bit different from what everyone else was using. I had come up with the awesome idea to use the same VMs at design-time as I used at run-time. This idea sounds very good, as it means that I only needed to build a single set of VMs and instead could switch the service implementations using DI. At the time, it sounded like the most “correct” solution. Little duplicated code, no chance of messing up the bindings and so on…but it has a huge problem…

I have recently tried using my VML on a project, and decided to throw it away almost instantly. Why? Well, it doesn’t work very well. Or rather it doesn’t work like it needed to. The functionality was spot on according to the design, but it didn’t work in the real world. Why? Well…

Imagine a simple Silverlight UI connected to a VM. The UI contains a drop-down with all the clients in the system. When a client is selected, the clients information is loaded, and the rest of the UI is populated. Having the UI gradually filled is a very common scenario. However, that is very hard to design if the VM doesn’t show all the information at once. So, with my VML it would just load up the clients, but I would never see the rest of the data as a client would never be selected.

So instead I guess we will have to use a duplicate set of VMs. One that we use at run-time and one that we can use at design-time. The design-time VMs should expose all data at once. Even if this gives the wrong impression of how the application will work, it will give us the ability to design all elements. It isn’t a great thing to do it like this. It is another set of code to keep up to date. Whenever a VM changes, it needs to be implemented in two places. But unfortunately it is a necessary evil…

So how do we do that? Well, it isn’t that hard. Just add an extra assembly with the design-time VMs. And yes…place them in a separate assembly. By doing this, you can package the application for release without having to include the design-time VMs. The other solution is to add big conditional compiler statement around the code and make sure it isn’t included in the release build.

After the design-time VMs have been created, it is time to use the d:DataContext attribute in Xaml. The xml namespace “d” should be defined as “http://schemas.microsoft.com/expression/blend/2008”. In VS 2008, I don’t think this was automatically added, and instead added when opening a Xaml file in Blend. But in VS2010, it should be there by default. There is also a namespace named “mc” defined. This offers the ability to tell the compiler to ignore certain namespaces when compiling. In this case, there is a “mc:Ignorable="d"” defined, causing the “d” namespace to be ignored.

d:DataContext defines what data context should be used at design-time and it is set by using a statement like this

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:MySolution.VM;assembly=MySolution"
d:DataContext="{d:DesignInstance Type=vm:ViewModel1, IsDesignTimeCreatable=True}"

 

As you see, we can use the d:DesignInstance to define what type to use at design-time. By just defining the Type, the new and AWESOME data binding property editor in VS2010 will be able to help you out with defining the data bindings. Is you also add IsDesignTimeCreatable, the tool used at the design-time will actually create a new instance and provide a data context while designing. This makes the UI easier to set up nicely as the values of data bound items are instantaneously visible in the designer.

You can also set the d:DataContext to d:DesignData. DesignData can use its Source property to locate a Xaml based file that contains the design-time data that you want to use. That way, you can build your design-time VMs in Xaml instead of code and have the tool pick up that as the data context. There is a lot more information about it here.

A lot of this is of course available through the UI of tools like Blend 4. There was support for design-time data in Blend 3, but there is even more in Blend 4.

The namespace “d” of course also contains some other useful things, such as d:DesignWidth and d:DesignHeight. These properties will set the size to use at design-time. And once again, all of this is used by Blend to make the design experience as good as possible.

So…even though my ViewModelLocator didn’t work as well as I had hoped, there are at least other ways to get a good design-time experience. And even a way to do it without 2 code bases…well…there will instead be some extra Xaml to take care of…

Ok…that’s it for this time…I hope this helps someone…

Cheers!

Pingbacks and trackbacks (1)+

Comments are closed