Design-time Data in Expression Blend 3

By Rob on Sunday, August 2, 2009

6 Comments

Filed Under: .Net, Blendability, WPF

Update: I’ve detailed another technique for implementing design time data in blend in this newer post (using something called DesignData)

How can you develop a complex GUI without ever needing to build and run it?

WYSIWYG tools have come a long way in recent years, and if you’re building a WPF app you can’t go past Microsoft’s newly-released Expression Blend 3. I’d always preferred Blend 2 over Visual Studio 2008 for building my XAML, not least because of the Silverlight support. But Blend 3 has some features that quite frankly put me in GUI developer nirvana. Sketchflow shows an awful lot of promise, but what’s really floating my boat is the almost undocumented design time only datacontext support. What does that even mean? Let me use a simple WPF game, Connect 4, to show you…

Lets say I’ve already built the game. Just pretend I’d even written most of the XAML by hand. Here’s what the game looks like when it’s just been launched:

running_startgame

and here’s a game that’s partway through:

running_midgame

Perfect! The game is finished. Let me tell you about how this was built:

First, I coded my ViewModel, a bunch of classes that the XAML binds to. I’ve implemented INotifyPropertyChanged where necessary, and am using ObservableCollections instead of Lists. Note that this is quite a simple game, and I don’t really have a Model (in the M-V-VM sense) to speak of:

viewmodel

The Game is the root of everything, it tracks the Players, whos turn it is, and the Columns. Columns have a collection of Cells, and Cells track whether or not  a Token has been placed within. I’ve exposed a Command on the Column class, which picks up mouse clicks through a tall, invisible button in my XAML.

The XAML for this game is quite straightforward. The window contains an ItemsControl for the columns, the column template contains an ItemsControl for the cells, and the cell template renders a blue rectangle with a hole in it, and an optional token. Grab the code and check it out if you like - you can download all this source at the bottom of the post.

Lets say that I had made this Viewmodel the datacontext of my main Window in the Window.Loaded event:

public void Window_Loaded(...){LayoutRoot.DataContext=new Game(7,5);}

When I come to edit the XAML in Blend (let’s say I was planning to make the UI look a bit foxier, with animations and gradients and whatnot), this is what I get:

No data in blend

Which is fair enough, because blend is effectively running my program with no data. The Window_Loaded event won’t be fired by Blend, Blend only works with the XAML. The Visual Studio WPF designer has the same problem:

Visual Studio with no data

A feature of WPF that has always existed, and is completely cool is that you can shift this datacontext declaration into your XAML (Note that the use of an ObjectDataProvider is optional. If we were using silverlight we’d turn these constructor arguments into properties):

xaml_datacontext

Even before Blend 3 came along, doing this would mean that Blend (and Visual Studio) would be able to render your XAML as though a game had just started:

blend_realdata

This is nice. Now we get a good idea of how the GUI will really look when it’s running. We can even edit the XAML Templates in place (to see what I mean, download the source, right click an ItemsControl and edit its ItemsTemplate). We’d be in big trouble, however, if our ViewModel tried to call anything external on construction. For example, if we were building a twitter client, we might start downloading tweets through a web service call. This may or may not work when your code is running inside blend, but you’d be working with variable results, and as soon as you have an exception your designer would die. Jonas Follesoe has a great post that talks about how you can leverage Dependency Injection to get design time data services and runtime data services going. Go read it – that’s the post that made me realise how cool and important it is to get realistic data into your design time experience.

Now that Blend 3 is out, however, we’ve got a new tool in our belt. I don’t know if you’ve ever tried to change the DesignWidth or DesignHeight of a UserControl or Window from Blend. This post explains it pretty well, if you haven’t… Well, Blend will go and add a bunch of namespace declarations to your XAML, the most important alias of which is “d”. You’ll notice that you can put d:DesignWidth in any element you like, and nothing will happen at runtime. If you’re lucky (or you put it in the right place), blend will pick up this design-time data, and will render your control at that width, but only from within blend. The fact that your XAML can contain directives that will only be executed / honoured / considered by Blend is quite a powerful one.  There aren’t very many of these attributes available, however,  Blend 3 introduced a big one: “d:DataContext”.

I stumbled across d:Datacontext when I was playing with Blend 3 and tried adding a “live datasource” to my window. I thought it was going to behave just like the old way of setting a DataContext, but when I ran my application, there was no data! I had a look at the XAML and saw that a Datacontext was being set on my root element, just like I expected. But why wasn’t this being applied at runtime? I had a really, really close look at the XAML and spotted the “d:” before the word datacontext. Sweet. I deleted that, and the app ran as expected. My next thought was to try setting both a design time (d:) and a run time (no d:) Datacontext. It worked!

So the upshot is, now we can write code like this:

Setting a runtime AND a designtime datacontext

Or we can even set the real DataContext at runtime through the Window_Loaded (or whatever) event. Why is this exciting? Now, it’s easyto have blend show a truly representative form of our gui at design time:

blend_designdata

This, by the way, was acheived with the following design time subclass of Game:

code_designgame

Simple, no? By using an ObjectDataProvider, we can even prevent the DesignTimeGame from even being instantiated at runtime. If you’re coding in silverlight, you’d use an alternative: “d:DataContext={d:DesignInstance vm:DesignTimeGame}”, which would only work with an empty constructor – which is fine, because even if the runtime game requires constructor parameters, we can just write an empty designtimegame constructor that passes some dummy ones in.

Now that we’ve got this design time data, it’s much easier to spruce things up in the XAML (note that I’m editing a template in-place, and that I deliberately coded the design time model to have a token in the top left cell):

Editing a template in place with DesignTime data

I can’t really express how much easier this design time data can make your coding. So please, download my example project, open it in blend 3, and try (for example) adding a gradient overlay to the tokens, or even just resizing them. I have to admit, I didn’t hand code the XAML, I blended it in about ten minutes once I had the design time data available to me. And I didn’t have to run it till I’d finished!

Download the Connect4 Source here

6 Comments for this post

Harshal

Great post. Unfortunately Blend isn’t included in MSDN subscription we have at work (at least that’s what I’m told).

Another similar problem I had while doing WPF was that, if I had database code in the constructor (or even loaded method? Can’t remember), VS2008 designer tried executing it but the connection string wasn’t set up at design time and so it would break and all I’d see in XAML designer was an error.

To get around that I did something similar, Just a check if its design time and instead of running whats in the constructor just drawing a simple Rectangle of that size. But I can’t see the actual interface that way. Hoping VS2010 designer will be better.

Posted onAugust 2nd, 2009 at 10:51 am
Rob

You should check that, because they changed the rules a while ago and Blend is included in most MSDN subscriptions, I believe. There’s a 60 day trial too – see if it speeds up your development…

Regarding your database access, I’ve done the exact same thing and you should definately give Jonas’ blog a read. Shifting your dependencies out of your viewmodel and into services will help make unit testing easier too!

Posted onAugust 2nd, 2009 at 11:27 am
Mike

Thanks for posting this

Posted onSeptember 11th, 2009 at 1:52 am

[...] Data in Expression Blend 3 http://www.robfe.com/2009/08/design-time-data-in-expression-blend-3/ a intresting exmaple of a simple game done in Blend [...]

Posted onNovember 4th, 2009 at 9:53 am

[...] designer) sees in Expression Blend is exactly what the finished product will look like? A while ago I posted about the d:DataContext attribute in Blend, and how you could leverage that to populate Blend with realistic sample data. What was awesome [...]

Posted onDecember 16th, 2009 at 11:59 am

[...] already blogged about the d:DataContext attribute, letting you set up a DataContext but only inside Blend. Another [...]

Posted onDecember 18th, 2009 at 7:58 pm

Leave a comment

Name (required) Comment
Mail (required)
Website