The simplest way to do design-time ViewModels with MVVM and Blend.
The problem is this: You’ve created your Views and ViewModels, but when you view them in Blend, you either see nothing, or the data you see is not useful for testing what you want in the view. There are various ways to deal with this, including writing code (either in the ViewModel or in a service locator) to return different data at design time.
I’m going to demonstrate a different way that doesn’t involve code, and is very simple and most importantly: Malleable.
- I have a ViewModel class called “BooksViewModel” that supports the search UI and result-set. This has some non-trivial properties such as a collection of “Book” classes.
- I have a View called “BooksView” that allows you to search for books, but I haven’t yet hooked up the data bindings (it’s easier to do after you create sample data).
- I have no code to differentiate between design time and runtime. The code is geared purely towards runtime.
What we’ll do:
- Use Blend to create some purely fake sample data.
- Assign the fake data as the data-context of the control you want, in a design-time-only fashion.
- Create the bindings and play with the data.
The “Before” picture: A view showing very little:
Step 1: Create some fake data with Blend:
Go to the “Data” tab, and create sample data from a class:
Select your ViewModel as the class to base the sample data on. This is a giant time-saver:
A new folder + file will be created: SampleData\BooksSampleData.xaml. It’s pre-filled with fake data and ugly namespaces. For readability, I’ve done a find/replace on the namespaces. Here’s what I get:
<m:BooksViewModel xmlns:m="clr-namespace:MVVM_DesignTime_Test.ViewModels" IsSearching="True" SearchError="Vestibulum cras" SearchString="Lectus fringilla eros"> <m:BooksViewModel.SearchResults> <m:Book Author="Aliquam aenean" Name="Curabitur maecenas class" Price="216.9"/> ...... <m:Book Author="Nec non" Name="Dictum etiam" Price="920.1"/> <m:Book Author="Elit fermentum enim" Name="Erat fusce" Price="597.75"/> </m:BooksViewModel.SearchResults> </m:BooksViewModel>
Two interesting things to notice about the above:
- It automatically generated multiple entries for the collection (“SearchResults”), as well as generating properties for each item in that collection (“Book”).
- Pretty much any class can be instantiated like this in XAML, so no matter how deep/complex the ViewModel and dependent Model objects, you should be able to play with them in the text editor.
Step 2: Assign the DataContext
This is where the magic happens. Look back at the Data tab, and see that this new sample data source is now listed:
Simply drag-drop this guy onto the control which should use it as the data context. The mouse cursor will display text explaining what it will do. In my case, I dragged it onto the LayoutRoot grid, since I wanted everything under that to use it. Once this is done, you’ll notice a new XAML attribute on that control:
This is the magic, especially the “d:” namespace declaration, which you’ll notice is mentioned in the page’s XAML declaration as such:
Basically, this tells everyone that they should ignore everything in the “d” namespace. But Blend chooses not to, and acts on it; this is why it works in design time without horking up the runtime.
Step 3: Create the data bindings
Now when you select the “Data Binding…” context-menu for a control’s property, it will show you the properties that come from this data context, which correspond to your ViewModel, with the correct names, types, etc:
And BAM – there’s the data:
- Clean up the crappy namespaces in the XAML to make things more readable.
- Change the data to whatever you like using the XAML editor.
- When you make changes and save, the UI will auto-adjust; this is so much quicker than editing code.
- When you make changes to the ViewModel class, remember to change corresponding properties to your sample data.
- You can have multiple sample data files for multiple ViewModels, and use them on the same page – just drag each one onto the control which should use it.
- This is especially useful in pivot and panorama apps, where one page actually houses a whole app with multiple ViewModels.