Following on from that previous post about real data, of course we can also make sample data in Blend at the document or project level over in the data tab;
All of those 3 menu options raised from the little icon with the drop down relate to creating sample data and whether you have “Project” or “This document” selected seems irrelevant as to where the sample data ends up.
New Sample Data…
If you go down this route then you’ll end up with a dialog asking where you want to put the data source;
and whether you want to leave the sample data in place when the application is running or not (i.e. make it real data).
The difference between the two affects what happens when you use items from the data source and whether they end up being set as the DataContext or the d: DataContext for the elements where you use them.
When you create one of these, you’ll find that it shows up in the Data tab;
and, if you’re of a curious disposition, then you’ll notice that it shows up in the project structure too;
Opening up that XSD in Visual Studio 2010 shows me that what I’m editing in Blend is actually an XSD;
I’ve never actually looked at how Blend does this but I’m guessing that it runs a transform on this in order to generate classes from this XSD because the generated MySampleData.xaml.cs has classes that match this structure. Here they are in a Visual Studio class diagram;
and then some piece of smarts knows how to take these bits and generate a XAML serialization of these types with test data slotted into it as you’ll find in the generated .xaml file;
<!-- ********* DO NOT MODIFY THIS FILE ********* This file is regenerated by a design tool. Making changes to this file can cause errors. --> <SampleData:MySampleData xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.MySampleData" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <SampleData:MySampleData.Collection> <SampleData:Item Property1="Aliquam class" Property2="True" /> <SampleData:Item Property1="Integer curae" Property2="False" /> <SampleData:Item Property1="Donec aenean cras quisque" Property2="True" /> <SampleData:Item Property1="Duis mauris nam" Property2="False" /> <SampleData:Item Property1="Etiam maecenas vivamus fusce" Property2="True" /> <SampleData:Item Property1="Nullam lorem nunc" Property2="False" /> <SampleData:Item Property1="Morbi aptent sed dis" Property2="True" /> <SampleData:Item Property1="Est praesent aliquam amet" Property2="False" /> <SampleData:Item Property1="Hac accumsan ante auctor" Property2="True" /> <SampleData:Item Property1="Arcu diam" Property2="False" /> </SampleData:MySampleData.Collection> </SampleData:MySampleData>
None of this matters too much. What matters is that you can shape the test data over in the Data tab in a fairly intuitive way by adding properties of type simple/complex/collection from the little menu;
Those pretty much speak for themselves and so if I was trying to build a representation of a set of people with a set of addresses then I might end up with;
but the data types over on the right hand side (highlighted) are all over the place so I can use the little drop down to try and fix them;
and that lets me choose between properties of type string/number/boolean/image (number is not an integer) and it also lets me apply various facets like length and so on to the data being generated.
I wish there were more data types – dates and times would be a good starting point. When it comes to using pictures Blend has the ability to read some from a folder for you;
and you’ll notice these show up in your project;
In terms of collections, you can always click on the icon and edit the details about the collection;
where you can tweak the data types and facets again and control the cardinality. You can even manually edit the data if you don’t like the generated values.
Import Sample Data from XML…
Another way to get data into the environment is to import it from an existing XML file.
I pondered over where to get an XML file from and then remembered my good old friend Northwind and I dug out an old FOR XML query I had kicking around on my disk somewhere;
select c.customerid [@id], c.country [@country], c.contactName [@contactName], c.contactTitle [@contactTitle], ( select o.orderid [@id], o.orderdate [@date], ( select od.unitprice [@price], od.quantity [@quantity] from [order details] od where od.orderid = o.orderid for xml path('item'), root('items'), type ) from orders o where o.customerid = c.customerid for xml path('order'), root('orders'), type ) from customers c where c.contactName is not null and c.contactTitle is not null for xml path('customer'), root('customers')
and I fed this into the “Import Sample Data from XML” dialog;
and that seemed to do a pretty decent job (once I’d fixed the problem I had with the text encoding) in that it showed up in my data tab as;
although it’s fair to say that all strings/dates/etc come in as strings with no particular facets applied to them.
It looks like a similar approach is taken – there’s a generated XSD in my project which looks like this;
and then some generated classes and a XAML file which contains the serialized actual data from my sample XML file persisted in a form that could be de-serialized back to the generated classes in question.
Create Sample Data from Class…
This was added in Blend 4 and is really useful if you’ve already got ViewModels kicking around that you can bring into the environment and have it make test data for.
If I’ve got classes such as;
public class PeopleData { public ObservableCollection<Person> People { get; set; } } public class Person { public string FirstName { get; set; } public string LastName { get; set; } public Uri Picture { get; set; } public AgeDetails AgeDetails { get; set; } public ObservableCollection<Address> Addresses { get; set; } } public class AgeDetails { public int Age { get; set; } public DateTime DateOfBirth { get; set; } } public class Address { public string HouseName { get; set; } public string AddressLine { get; set; } public string PostCode { get; set; } } }
then I can add a sample data source around this, picking my data class from the dialog;
and I then get that new data source which always seems to go into the Project rather than the current document although I daresay that you could move it manually. The data source shows up in the Data tab;
with more type information than any of the other mechanisms I’d tried and it’s interesting to see Int32 and Uri and DateTime show up there.
Now, when I look at the project here there’s no XSD created. There’s just a XAML file;
and there’s no editing experience for this sample data from the Data tab. Trying to edit just drops me straight into the XAML editor for that file. That is, clicking this;
equals this;
and it’s quite interesting because I think all of the DateTime values are set to the equivalent of DateTime.Now when the generation happened but the Integer values look to have been randomised and the Uri values look to have been omitted.
So, it’s a little hit-and-miss but it’s a lot better than having no data whatsoever at design time.
Using the Sample Data
Once you’ve got the sample data created via one of the 3 mechanisms then it’s into a drag/drop in order to make use of it on the design surface. You can work in either List/Details mode and if you’re in one of those modes then holding down the ALT key during a drag will temporarily move you to the other mode for that operation.
If I drag something like the People collection out onto the design surface then I can see 1 of three things.
A regular drag (in list mode) offers to create a ListBox and bind its ItemsSource to People. Automatic!
if I hold down the SHIFT key then I see instead;
which will pop that very familiar dialog rather than just assuming I want to make a ListBox and set its ItemsSource (which is a good assumption usually);
and if I hold down the CTRL key then I see;
and finally if I have both ALT+SHIFT down then it’ll give me;
By default if I go with dragging that People collection to the design surface then I get a ListBox with an ItemTemplate which displays the FirstName, LastName, Picture
If I wanted to also include the Age then I’d just edit the template and drag it out there;
and if I (say) wanted an Expander that displayed the addresses in a TreeView (yes, I know – this is nuts) rather than a ListBox then I can create the TreeView in the Expander and then drag the Addresses out to that TreeView;
It’s worth saying that I could have selected a subset of properties if I wanted a template based around them – e.g. starting again here but only selecting the FirstName and Picture property and dragging them to this new TreeView;
and then if I want to build up a details view I can drop a Grid over on the right hand side and then in details mode I can drag out some properties like FirstName and Picture again and Blend will make me some controls.
and it’s “kind of” interesting as to the binding that Blend throws out for this. It sets that Grid’s DataContext 2 ways;
<Grid DataContext="{Binding SelectedItem, ElementName=treeView}" d:DataContext="{Binding People[0]}">
one for design time and one for runtime. The rest of the bindings within the grid are standard. And then if I wanted to display the addresses here maybe in a DataGrid then I can just draw a DataGrid onto the surface (setting its AutoGenerate property to true) and then in list mode drag those addresses to that DataGrid;
Dragging/Dropping Methods/Commands
It’s probably worth saying that if you have created sample data from a set of .NET classes then you might have methods or ICommand implementations on the classes here like this one I just quickly added to my Person class;
public class Person { public void ShowInMessageBox() { MessageBox.Show( string.Format("{0} {1}", this.FirstName, this.AgeDetails));; }
then they’ll also show up in the Data panel and you’ll find that you can’t drag like this;
but you can drag out the FirstName (e.g.) to make a ListBox then edit the ItemTemplate for that ListBox and add some piece of UI (e.g. this star shape below) and then drag the ShowInMessageBox method to that star shape;
and that will create triggers and actions from Blend but that’s really another story…