Udostępnij za pośrednictwem


Introducing sample data for Developers

Blend 3 brings to the table really sophisticated support for sample data, enabiling better designability of your applications. In my previous post, I demonstrated how designers could leverage this feature to prototype data connected applications inside Blend . However, for really sophisticated applications, richer support might be desirable - for example, you might want to use your own custom types for sample data in the cases where you cannot re-create the schema from scratch using the primitives that we provide. 

Here is a small example that will help you get started on a feature that we just introduced in recently available Blend 3 build – we call this feature “design data”. This feature allows developers to enable designers to be more productive inside Blend for practical LOB applications where there is a clear separation between model and view, and where you can’t use the Blend sample data feature as your UI might depend on your custom business objects (for example, think typed data templates in WPF).

Design Data Sample

 

Let us take a quick tour of this example, and see how things work behind the covers:

 

ShoppingCart.cs defines a data structure that we are trying to visualize in ShoppingCartView.xaml. The type ShoppingCart does not have a public constructor, neither does ShoppingCartItem. Similarly, ShoppingCart has a read-only property ItemsCount. These kinds of limitations are extremely common in real-world data structures (and is being demonstrated here to show how our system handles these limitations just fine, without requiring your to make changes to your run-time code)

 

The sample data for ShoppingCartView.xaml is defined in ShoppingCartSampleData.xaml, which is included with a special build item type in the project file: <DesignData Include="ShoppingCartSampleData.xaml" />. This ensures that you don't pay any run-time penalties for enabling this design-time only feature.

The contents of ShoppingCartSampleData.xaml look like following:

<local:ShoppingCart

      xmlns:local="clr-namespace:DesignDataSample;assembly=DesignDataSample" ItemCount="22">

      <local:ShoppingCart.Items>

            <local:ShoppingCartItem ItemName="Book Name 1" ItemDescription="A very nice book!" ItemImage="/DesignDataSample;component/MySampleDataImages/Tree.jpg"/>

      </local:ShoppingCart.Items>

</local:ShoppingCart>

 

There are a few things to note about the contents of this file:

a) While the format is XAML, we have relaxed the specification quite a bit. You are allowed to specify a value for the read only property (ShoppingCart.ItemCount, ShoppingCartItem.ItemName), as well as initialize objects that don’t have public constructors (ShoppingCart, ShoppingCartItem). Blend creates on the fly types which look like user types. You could choose to prevent reflection (in which case, what you can specify in XAML is severely restricted) by specifying <IsDesignTimeCreatable>true</IsDesignTimeCreatable> in the project file for the sample data XAML item.

b) You can specify any platform type like Brushes, ImageSource, Uri, etc.

c) You get full intellisense in Blend for typing this XAML.

 

In ShoppingCartView.xaml, we then hookup the sample data like so:

<Grid x:Name="LayoutRoot" d :DataContext="{d:DesignData Source=ShoppingCartSampleData.xaml}" Background="#FFB2B2B2">

 

For WPF projects, if your XAML was using typed data templates, you need to add the following attribute to those typed data templates to get picked up automatically, if you were using the reflection based sample data types and you wanted a good design experience.

<DataTemplate x:Type="{local:Foo}" d :IsDesignTimeCreatable="False" >

 

This particular sample data feature will also be supported in VS 2010. As always, please don't hesitate to ask for further clarifications, and I really value your feedback on how we could make this feature more useful for you.

Comments

  • Anonymous
    July 13, 2009
    Could you release walkthroughs on how to convert the sample data bindings to use with production connections?   Could you include a basic demo for items like LINQ to SQL Class?  Another with new .NEW RIA Services?  BTW, what kind of support will Blend 3 have with RIA Services?  Thanks in advance.

  • Anonymous
    July 17, 2009
    Can you go into more detail about what the d:IsDesignTimeCreatable property does?  Also you didn't mention the d:DesignInstance property.  Is there any connection between d:DesignInstance and DataTemplates?  I've created some custom controls that have dependency properties that are custom types without a default constructor, and I'm having trouble getting this to work.  I am suspecting that the dependency property isn't getting set because the design time created type doesn't match the type of the dependency property.  Does this sound like what may be happening or am I missing something?  And if so, then is there anything I can do about it?

  • Anonymous
    July 17, 2009
    Hi Joey, Please feel free to get in touch with me at unnir at microsoft dot com with a sample sample that demonstrates your problem. I can investigate and help you out with a solution. Thanks, Unni

  • Anonymous
    September 16, 2009
    Two questions: (1) When I open this project in VS, it tells me that "ShoppingCart" and "ShoppingCartItem" aren't usable as object elements because they don't define a public parameterless constructor.  That makes sense -- so why are they usable? (2) How do you use this approach for complex object graphs, for instance, if you have a Customer with Orders with OrderItems with Products?

  • Anonymous
    September 16, 2009
    Never mind, figured it out for both of them: (1) As you mention in your article above, Blend isn't really creating the objects, it's just creating objects that look like the objects you're defining.  Sorta like "duck typing". (2) I was able to get XAML like this working: <rs:Room d:IsDataSource="True" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:rs="clr-namespace:SlideLinc.Client.Common.RoomService;assembly=SlideLinc.Client.Common" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" mc:Ignorable="d" Name="_default" OwnerID="smithkl42" > <rs:Room.Owner> <rs:RegisteredUser x:Name="smithkl42"  UserID="smithkl42"  Email="smithkl42@gmail.com"  FirstName="Ken" LastName="Smith" MaxFileUploadSize="20000" UserName="Ken Smith" /> </rs:Room.Owner> <rs:Room.Sessions> <rs:Session> <rs:Session.User> <rs:RegisteredUser UserID="smithkl42"  Email="smithkl42@gmail.com" UserName="Ken Smith"/> </rs:Session.User> <rs:Session.Whiteboards > <rs:Whiteboard /> </rs:Session.Whiteboards> </rs:Session> <rs:Session> <rs:Session.User> <rs:RegisteredUser UserID="johnsmith"  Email="smithkl42@gmail.com" UserName="John Smith"/> </rs:Session.User> <rs:Session.Whiteboards > <rs:Whiteboard /> </rs:Session.Whiteboards> </rs:Session> <rs:Session> <rs:Session.User> <rs:RegisteredUser UserID="bobsmith"  Email="smithkl42@gmail.com" UserName="Bob Smith"/> </rs:Session.User> <rs:Session.Whiteboards > <rs:Whiteboard /> </rs:Session.Whiteboards> </rs:Session> </rs:Room.Sessions> <rs:Room.SharedFile> <rs:SharedFile OriginalFileName="Some Shared File.doc" /> <rs:SharedFile OriginalFileName="Another file.docx" /> <rs:SharedFile OriginalFileName="A Presentation Of Some Sort.pptx" /> </rs:Room.SharedFile> </rs:Room> I still haven't figured out how to point later object references back to earlier objects, but I don't think that's critical for most things.

  • Anonymous
    September 17, 2009
    Hi Ken, Yes, you are right - we use reflection to generate dummy types on the fly so we can instantiate them, and yet have the the same signatures for properties, etc. The objects are really supposed to be only for visualization purposes, so things like pointing back to existing instances might not work - you might just need to duplicate them. Thanks, Unni

  • Anonymous
    November 19, 2009
    Hi Unni, I have played with the DesignData build action and it’s absolutely gorgeous. I have noticed one somewhat strange behavior. If a class has a property of generic type, Blend fails to create a duplicate for this entire class. There are two minor variations of this:

  1. If the “faked” class has no default constructor, Blend will say:” The type ... does not include any accessible constructors”
  2. If the “faked” class does provide a default constructor, Blend will accept it in the.xaml file but won’t display the actual data in design time.
  3. If the generic property is commented out, everything is fine. My question is: Can you please explain this behavior to us and what is more important, tell us if there is a work-around for that. If the generic-type property is declared with an interface instead, this will hide the generic type inside the “get” accessor of the property and this will obviously work, but there is no guarantee it will be applicable everywhere. If we don’t really need to provide data for those “problematic” properties it would be absolutely sufficient if we could exclude them from the generated “fake” type (maybe using an attribute like [Browsable(false)], etc. ). Probably you would come with a better idea? Here’s a demonstration for this. The code file looks like this: namespace WpfApplication1 {    public class Test    {   //Default constructor   //public Test(){} – commented out   //Constructor        public Test(object initializer){}        public int SimpleProperty { get; set; }                public ObservableCollection<Item> Items { get; set; }   //Property using a generic   public BusinessOperation<Delivery> Operation { get; set; }    }    public class Item    {        public string Name { get; set; }    }    public class BusinessOperation<T>    {        public T SomeData { get; set; }    }    public class Delivery    {        public string TrackingNumber { get; set; }    } } ... And .xaml file with DesignData build action looks like this: <local:Test xmlns:local="clr-namespace:WpfApplication1" SimpleProperty="4"> <local:Test.Items> <local:Item Name="Item1"/> </local:Test.Items> </local:Test>