Downloads
DesignWithData.Final.zip

I'm a developer of forms-over-data business applications. I have no graphic arts skills and I'm not hired for those skills. My client is paying for functionality on a deadline, not glitz. Microsoft might preach about designers and developers working together, but I’ve never seen a designer and I’m not going to see one on this project. I'll be the designer and I'll do my best. The UI won’t be pretty but it will do the job.

Have you heard that speech before? Have you given that speech before? I have at least a hundred times. Some of it's even true. I am artistically challenged. I am, like my client, suspicious of geegaws and gradients on an internal-facing application. My client has never seen a good looking line-of-business application and doesn’t expect one now. She has a tight budget and a short deadline. She won’t hire a designer.

In truth, the speech is evasive and a tad dishonest. Painting controls on the glass is central to my practice. The client is paying me to build the application UI. In my spare time you’ll find me obsessing on the latest Visual Studio tricks and writing templates in ReSharper. The exercise is familiar and comfortable and will make me a marginally better programmer. But learning design tools to build better user experiences would have a far higher return for me as a developer of business applications. Unfortunately, UI design is foreign territory.

The speech is also fundamentally wrong. The client doesn’t want functionality. She wants an application that helps end users do their jobs effectively. That’s what she wants to pay for. I’ve told her she can’t have that; she can have functionality. Sadly, she'll accept my offer, hoping that I'll deliver an acceptable user experience with the time and money in her budget.

In return for her good faith, I'll squander a good portion of that time and money. Because I don't know or care about tools and techniques for UI development, I'll take longer to deliver an inferior product.

We Can Design Better

I could do better. You can do better. You just need a place to start learning. Let’s start with something you know; let’s start with data. How do you build a screen that shows application data?

In this article, I’m not going to talk about designing the screen. That would drag us into the deep end of the graphic arts pool. I’m going to talk about the development process; about what you do as a developer when you build a screen.

Enter Northwind Traders. Let's say that Northwind Traders has hired you to move their legacy application to Silverlight. They want customers to enter and manage their own orders on the Web with the same responsive experience as their current Windows Forms application. You'll begin by reworking the Northwind product catalog management screens.

Northwind buyers spend their days on the phone, searching the globe for the best products at the best prices. They dutifully record their discoveries in the Product Management screens that you'll build.

Northwind buyers are internal employees. Sally, the project manager, doesn’t see the value of an artful user experience. However, she has noticed that the buyers make many data entry errors and she hopes that during the rewrite you'll use some of Silverlight’s graphical strengths to create a less error prone design. When she told you this, you gave your speech and promised to “do my best.”

A Poor User Experience

Nobody cared about the user experience the last time either. The current screen consists of a dozen or so user controls arranged neatly in rows and columns. There is some semblance of order but no particular emphasis and no obvious work flow. The main consideration was to display all of the Product data fields.

Of course, you spend the first week or two mapping entities to the database and writing a service layer to retrieve them. When you get around to the first screen, you’re thinking it will be a throw-away. You watch a video on the new Silverlight UI designer in Visual Studio 2010, then you drag-and-drop your way to your first attempt. When run it looks like Figure 1.

The content area is a grid with three columns. Column one holds a list of products in the DataGrid; column two, the detail for the current product in a DataForm; column 3 contains a bordered image of the selected product. The screen is hideous. The order of the fields makes no sense. All input control widths are the same no matter what the values; the maximum unit price is a $1,000 but it’s the same width as the product name and description. At least the screen is functional.

As you recall how you got here, you find yourself grateful for Visual Studio 2010. Now you can examine and manipulate the Product Manager screen with its visual design tool instead of having to hack at the XAML as you did in Visual Studio 2008. Now you can get a vague idea of what the screen (Figure 2) will look like before you run the application.

At runtime, the DataForm in the second column will automatically generate the labels, fields, and bindings of the product details. You didn’t have to lay them out. You’re thinking that’s a good thing because Figure 2 reflects roughly your 30th attempt to draft this screen. You spent all day hooking up the development database, aligning the controls, adding the splitter, and tucking in that image. Just setting the border around the image required 5 iterations. The whole mess took far longer than you anticipated. You console yourself with the thought that it is still early in the project. You should expect hiccups.

Despite your best effort, you blew the budget for this screen. You told Sally that you weren’t a designer and you got that right. Maybe you should just move on to the next screen.

Examine Your Development Process

Stop. What is your development process? You drag controls around on the art board, fiddle in the property window, and drop into XAML a few times. But you can’t tell what the screen will look like when it runs. You do have a rough visual outline which is a decided improvement over exercising your imagination with raw XAML. But without data, you don’t know if this screen makes any sense. You don’t know if the column widths are appropriate. You're praying something good happens in the DataForm. The image control may or may not be ok.

The only way to find out is to compile and launch the application and let it populate the screen with data from the development database. Maybe you scribble a few notes. Then you shut down and wait for Visual Studio to rebuild the art board so you can try again. I timed you; it took 40 seconds to complete this cycle.

Do the math: 40 seconds times 30 iterations is 20 minutes. For 20 soul-stealing minutes you stared at a monitor hoping futilely that this would be the final pass. Twenty-nine times you returned to nudge a control to the left or increase a border width. During each 40-second cycle you were so numb with boredom that you almost forgot what you were fixing. After iteration 30 you gave up and declared victory with a design that disappoints even you. In truth, you'll revisit this screen again and again over the coming months, trying to coax it into an acceptable degree of utility. You remember again why you hate UI and wish you could stick to writing WCF services.

It will get worse. Right now the application is only one screen. You haven’t integrated it into the larger application yet. Someday soon it will take much longer to compile and load. You will login and navigate through a maze of other screens until you finally arrive at the Product Management screen. Forty seconds will become two minutes. I have seen five minutes.

An Improvement: Using Sample Data

In this article, we’ll concentrate on one improvement. We'll display representative sample data in the screen while we design it. This single change will dramatically reduce the number of design-compile-run cycles. Reducing those cycles does more than save time. It yields a demonstrably better screen design without requiring any graphic arts skills.

You'll need Microsoft Expression Blend 4. I hear it’s a designer’s tool. Well it’s a developer’s tool too. It retails for $600, which is steep to be sure. On the other hand, a professional appreciates the value of good tools. If you can’t recover the cost in 10 hours doing just what I’m about to show you, then you aren’t trying. Download the free trial and give it an honest try.

In the accompanying code, I’ve opened the application solution in Blend and opened the MainPage.xaml screen (also called the “view”). MainPage is the slightly altered result of creating a Silverlight application project with the Metro-themed “Silverlight Navigation” template.

I’ve got Visual Studio 2010 open to the same solution. It’s easy and painless to toggle between Visual Studio and Blend while they share a solution. We’ll spend most of our time in Blend. But Visual Studio is much better when we have to drop into the code.

Returning to Blend, we create some sample data for the Product management view. That process begins on the “Data” window. As Figure 3 shows, I’ve highlighted the disk-drive icon and selected New Sample Data.

The subsequent steps are

  1. Initiate creation of a ProductSampleData data source for the project
  2. Agree to let the design data be our runtime data for now.
  3. Define the sample data Product properties that we want to see on this screen.
  4. Review and edit some of the sample data.
  5. Make a ListBox by dragging the product image property into the first grid column
  6. Tweak it to include the ProductName
  7. Make a DetailsGrid by shifting to Details Mode and dragging the product name into second grid column.
  8. The product name should rivet the user’s attention; apply an existing style to make it prominent

Figure 4 shows what the designer’s “art board” looks like following the last step. I glossed over the exact sequence of mouse moves and key strokes. You can review the details in the video that accompanies this article

Get Input from Users

Setps 3 and 4 warrant discussion. In step 3, I define the properties of the ProductSampleData collection. I tend to base the sample data properties on the entity model, but not slavishly. We don’t have to define every property in the model. We should think about what data truly belongs on this screen. You did spend time with a live user or at least a business analyst to uncover what the user is supposed to see and do here, right? No? Then stop right there and do the leg work.

In the real world, you’ll probably have to make some of it up. Either the client won’t let you talk to anyone or you’ll discover that no one actually knows how it is supposed to work. A good developer is a perceptive interviewer who learns the business domain. That will take time. Meanwhile, you can look to the legacy application for clues. Use the Product entity properties as a guide and cherry pick the ones that make sense.

You’ll likely find half a dozen fields that make no sense to anyone. Although no one knows what these fields mean, everyone is afraid to drop them. You might not be able to remove them but you can diminish their importance by squirreling them away in an “advanced” area that is collapsed by default. Find an unobtrusive place for the “advanced” area, make a note, and then ignore the fields. Take comfort in the fact that you can change the sample data structure and values later when you have to display these fields.

In step 4, we review the design data values. As we add sample data properties, Blend busily generates matching sample data values in a file called “ProductSampleData.xaml”. Figure 5 shows the XAML for our example.

You’ll want to change some of these values to better approximate real world data. You can hack the XML, if you're careful. Remember that altering the property definitions later could cause the sample data generator to overwrite your changes. Fortunately, we rarely have to visit the XML. Blend provides a built-in sample data value editor that is sufficient most of the time. Figure 6 shows changing a generated product name to Widget.

The First Run

We’ve done plenty for our first time in Blend. Now we want to see the screen in action. Remember that we told Blend in step #2 to use our sample data when the application executes. Hop over to VS and run just this Silverlight application project by selecting “Debug | Start new instance” from the context menu.

The browser pops right up! No launching of an application server, no awakening Entity Framework or the database, no retrieving of data. I can compile, run, and return to Blend in 6 seconds.

We continue to tweak in Blend until we reach the final version for the day. I cover the bump and grind of every detail in the accompanying video. Figure 7 and Figure 8 show the final design and runtime views; they seem remarkably similar to my eye.

Details aside, I was struck by several important differences in the development process. When I tried this exercise, I ran the application 6 times—not 30—to confirm that what I was seeing at design time rendered appropriately at runtime. Like you, I'm not a designer and I’m new to Blend. If I were competent, I would likely have cycled only two or three times. Still, I was working almost continuously in Blend. I didn’t break my flow every few changes to run the application as I did with the first design effort. When I chose to run the app, I had no difficulty maintaining focus for the six seconds away from Blend.

I found myself making better graphical choices. The sample data told me how much space to reserve for the product name, image, price, and description. Seeing representative values next to each other helped me position and style the controls to fit the end user’s workflow.

The user’s primary task on this screen is to update product prices. That task entails (a) finding the appropriate product to update and (b) entering the new price. As I imagined my interviews with workers and supervisors, I heard them say that entering prices into the wrong product record was a common error; that’s an easy mistake to make when the screen is dense with text of the same font size.

I made the product name and picture bigger and surrounded them with white space. I saw that the ListBox items container showed only one product per line. You often had to scroll several pages to reach the intended product. I can reduce scrolling if I can get more products into the ListBox. This realization led me to replace the ListBox’s standard-issue StackPanel with a WrapPanel.

I made the price textbox bigger than other data entry controls so the user can quickly find and edit the values. The product description is less relevant to the primary task so I made it smaller and dimmer.

All of these ideas emerged from seeing the sample data as I was designing the screen. I would not have thought to try any of these adjustments without seeing the problems and the opportunities right there in the designer. That’s why designing with sample data is great.

Inside the XAML

I am instinctively suspicious of generated XML, a reaction borne of long and unhappy experience. I am pleased to report that Blend-generated XAML is remarkably clean. It’s quite easy to discover how the “Design Data” feature works.

We’ll start from data binding and work back to the sample data. The Product screen is a UserControl that wraps a border control holding the screen content. There is nothing special or sacred about the Border control; it could have been any container control. This particular arrangement is an artifact of the Silverlight Navigation Application template from which we began. Blend bound the border’s DataContext to a StaticResource called ProductSampleData:

<Border DataContext="\\{Binding Source=\\{StaticResource ProductSampleData\\}\\}" >

We won’t find the ProductSampleData resource in MainPage.xaml. We told Blend to make the sample data available to the project as a whole, not just to this screen. We’ll have to look up the visual tree to find it.

“Up” in our application takes us to App.xaml. The screen project happens to be the same as the Silverlight application project so Blend will place our sample data among the application-wide resources. Open App.xaml and we’ll find that the XAML specifies a resource of type ProductSampleData as Figure 9 shows.

Recall that Blend generated sample data to a XAML file of that name and put it in a project level “SampleData” folder. The companion XSD describes the properties we entered in the Blend “Data” window and gives us IntelliSense support in Visual Studio. A neighboring subfolder holds the image samples; they are included in the project with the “Resource” build action.

We took a peek at ProductSampleData.xaml in Figure 5 and saw an XML representation of data as a graph with a root node called ProductSampleData. At runtime, Silverlight reads the XAML and builds a ProductSampleData graph of .NET objects; Blend and Visual Studio imitate that process at design time.

Thus we've traced the path from a DataContext in our screen to a resource in a dictionary to the XAML representation of the sample data and, ultimately, a runtime object graph of concrete objects.

Note that we developed our Product Management screen in the main Silverlight application project. Had we written it in a supporting Silverlight class library, we would navigate in similar fashion from a DataContext to a resource in a resource dictionary to a XAML file with sample data.

Design Time Attributes

Return to the screen XAML and search for DataContext. It appears twice. We saw the border’s DataContext, which is the ambient DataContext for all bindings in this screen. Blend also specified a DataContext for the DetailsGrid that hosts the product details as shown below:

<Grid x:Name="ProductDetailsGrid" Grid.Column="1"

        DataContext="\\{Binding SelectedItem, ElementName=listBox\\}"

      d:DataContext="\\{Binding Products\\[0\\]\\}"

There are two DataContext assignments. The first makes perfect sense. When we run the application, the ListBox holds multiple products and the Grid shows details about the one product that is currently selected. The ListBox and the Grid are related as master to detail. It follows that the grid should bind to the selected item of the ListBox.

The second DataContext binding is peculiar. Notice the “d:” in front of the DataContext attribute. That’s the xmlns prefix associated with a special namespace that governs design tool behavior. Whenever you see an attribute prefixed with “d:” you know the attribute is for designer usage only. All “d:” properties are ignored by the compiler and excluded from assemblies.

This d:DataContext tells the design environment (e.g., Blend or Visual Studio) to use this binding while displaying data on the art board. The tool should ignore the binding of the real DataContext.

Evidently, Blend thinks we should bind the grid’s DataContext differently in the design environment. Because there is no Source attribute, the grid is bound to the ambient DataContext which is the ProductSampleData resource. That resource has a Products collection property. Binding to Products\\[0\\] will associate the Grid with the first sample product in the collection.

The light bulb goes on. The ListBox isn't alive at design time so there could be no SelectedItem value. The DetailsGrid won’t display sample data without a SelectedItem value. Clearly we can’t use the runtime binding. On the other hand, the Products collection is populated at design time. Binding to its first product yields data for the DataGrid. The mystery of two DataContexts is solved.

Running with Real Data

Eventually, we must see the application display “real” data. Real data isn't necessarily more real than sample data. At first the data will come from your development database. The example code doesn’t even have a database. It produces fake data in a manner that simulates an asynchronous request to a remote server.

By “real data” I mean data delivered by the application’s data access machinery, not the sample data Blend stuffed in a resource file. We switch to the real data in three steps:

  1. Disable the sample data during execution
  2. Connect the screen to the products retrieved by your application
  3. Tweak a few bindings

Return to the Data window and uncheck the Enable When Running Application option for the ProductSampleData data source. Blend makes a single change to the binding of the Border DataContext, switching to the “d:”, design-time-only variation. The revised binding follows:

<Border d:DataContext="\\{Binding Source=\\{StaticResource ProductSampleData\\}\\}" >

You'll know how to wire data to your screen. In the example application, I added a Loaded event handler to the screen’s code-behind. The handler sets the screen’s DataContext to a new instance of a MainPageViewModel class. The entire method is two lines:

    private void UserControl_Loaded(object sender, RoutedEventArgs e) \\{

      if (DesignerProperties.IsInDesignTool) return;

      DataContext = new MainPageViewModel();

    \\}

In the first line, the handler bails out if executed in the design environment. That’s a critical step. Our application should not call the database while we’re in Blend. It will probably fail but you should prevent it in any case.

The second line sets the DataContext to a new instance of MainPageViewModel. That instance has a Products property, named and structured just like the Products property of the ProductSampleData data source. The screen was already binding to a Products collection at design time; those bindings will “just work” with the ViewModel’s collection. The symmetry between sample data and ViewModel is no coincidence. Blend’s design data support plays well with the Model-View-ViewModel (MVVM) pattern.

Finally, we’ll need to adjust some of the bindings. The number and kind of adjustments depends upon the controls and data in your application. Some of your sample data properties won’t match your real data properties. Maybe the types returned will be different. Maybe the values aren’t quite right.

In our example code, the “real” Product’s ImageUri property returns a portion of the image address. We used a ValueConverter to build the full address back in our first screen design. Maybe we can use it again here. Accordingly, we adjust the image bindings in both the ListBox and the DetailsGrid:

<Image Source="\\{Binding ImageUri,<br>    Converter=\\{StaticResource ModelImageUriConverter\\}\\}" ...

Watch out! The sample data ImageUri doesn’t need conversion. In fact, the ValueConverter will mistranslate the sample data ImageUri; the image will disappear from our design view.

Unfortunately, there is no way to specify alternative design-time and runtime bindings. In this example, we finessed the problem by modifying the converter to work with both sample and real ImageUri data.

We can’t detect every problem in the designer. The DetailsGrid does a fine job of displaying product information on the art board. But when we run the application, the DetailsGrid is blank. It fills with product information only after we pick a product in the ListBox. That’s annoying. What is wrong?

At runtime, Silverlight binds the DetailsGrid to the ListBox’s SelectedItem property before the product data arrive. The collection is empty. There can’t be a current item so the SelectedItem property returns null. Having no product to bind, the grid too is empty. Surprisingly, the ListBox SelectedItem value remains null even after the products arrive.

Lucky for us, the MainPageViewModel implements INotifyPropertyChanged and has a CurrentProduct property that raises the PropertyChanged event when set. Luckier still, the ViewModel sets the CurrentProduct to the first product after the product data arrive. We’ll get the desired behavior if we bind the ListBox’s SelectedItem property to the

ViewModel’s CurrentProduct, as shown below. All these details are covered in the video. Figure 10 shows the final product.

SelectedItem="\\{Binding CurrentProduct, Mode=TwoWay\\}"

What We've Learned

Blend is a developer productivity tool. You don’t have to be a graphic designer to use it. You can pick up the basics in a few hours—hours you’ll  soon recover when you incorporate design data in your process. You’ll produce screens more quickly with less pain and those screens will be palpably better than the ones you’ve been drafting the old fashioned way.

You don’t have to compromise your architectural principles either. Blend and design data work fine with separated UI patterns like Model-View-ViewModel. We touched upon that in our final example. We should explore it further, but that’s an adventure for a future article. To become a better, more productive business application developer, you'll have to break old habits and learn something new. That’s my idea of professional fun. Enjoy!

 

Learn More

Authoring for Microsoft Silverlight 4 with Microsoft Expression Blend," a TechEd 2010 Video by Alan Gasperini.

Sample Data in the WPF and Silverlight Designer,” a 6/30/2010 post by Karl Shifflett.

 “d:DesignInstance, d:DesignData in Visual Studio 2010 Beta2,” a post by Karl Shifflett.

 “Introducing sample data for Developers,” a post by Blend Program Manager Unni Ravindranathan.