Using d:DesignSource for design-time DataGrid grouping with sample data

I recently had the need to use the row grouping feature of the WPF DataGrid.

As you know, in order to design with Blend effectively, you really need to have data displayed at design-time. It’s fairly straight forward to use combinations of d:DesignContext and d:DesignData to achieve that goal. In the case of DataGrid, you can bind ItemsSource directly to a collection in your design-time model.

The question is: How do you use design-time data and grouping at the same time?

The reason the solution is not obvious is because the DataGrid’s grouping feature relies on having a PropertyGroupDescription configured for the CollectionView that the DataGrid’s ItemSource is bound to. If you bind ItemsSource directly to a collection, you do not have access to the CollectionView at design-time.

Just to confuse things, if you Google for DataGrid grouping you will find a plethora of out-of-date articles suggesting you can configure the grouping by using the DataGrid.GroupingDescriptions in Xaml, which you can’t (it only worked on older/beta versions). On the other hand there are several articles which describe how to configure grouping programmatically. The problem with the programmatic approach is it does not run at design-time, and is in conflict with the design-time attributes. I want to use the well supported design-time sample data tool chain, and keep designers free from having to write code.

While Googling for a solution I came across the new design-time attribute documentation (note: it applies equally well to WPF in spite of the Silverlight bias!), which included an attribute I had never seen before: d:DesignSource. According to MSDN d:DesignSource

Specifies a design-time data source for a CollectionViewSource. This makes the designer aware of the shape of your types. This enables you to use the data binding builder to create bindings.

<CollectionViewSource x:Key="CustomerViewSource"
  d:DesignSource="{d:DesignInstance
  local:Customer, CreateList=True}" /> 

The description was intriguing but after looking at the code sample it seemed to be mistakenly underselling the capability. The sample code shows that it does more than make the “designer aware of the shape of your types” – it’s actually allowing sample data to be injected into a CollectionViewSource using the well know d:DesignInstance … and presumably d:DesignData too.

As it turns out, the only way to specify the DataGrid grouping in Xaml is to use the CollectionViewSource. I figured by combining CollectionViewSource and d:DesignSource I could achieve my goals.

After some experimentation I got it working exactly as I hoped it would. Here is the code:

    <Grid>

        <Grid.Resources>
            <CollectionViewSource x:Key="groupedCollectionView"
                                  d:DesignSource="{d:DesignData Source=./SampleData/BookingRowCollectionSampleData.xaml }" 
                                  Source="{Binding RuntimeBookingRowCollection}">
                <CollectionViewSource.GroupDescriptions>
                    <PropertyGroupDescription PropertyName="PropertyToGroupBy"/>
                </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
        </Grid.Resources>

        <DataGrid AutoGenerateColumns="True"
                  ItemsSource="{Binding Source={StaticResource groupedCollectionView}}" >
            <DataGrid.GroupStyle>
                <x:Static Member="GroupStyle.Default"/>
            </DataGrid.GroupStyle>
        </DataGrid>

    </Grid>

There are a couple of things to point out:

  • I used “Create sample data from class…” in Blend to create my BookingRowCollectionSampleData.xaml. The class which I generate from was defined below. I found I had to create this specialized collection in order to satisfy the d:DesignSource. Conversely my attempt at creating sample data based off my view model which in turn had a collection property was a dead end – d:DesignSource needs to be given a raw collection; there is no way to dereference the collection property within a view model.
        public class BookingRowCollection : List<BookingRow>
        {
        }
  • I wanted to make sure that I didn’t need multiple paths in my code behind to handle the differences between design-time and run-time, specifically with binding and MVVM. In this case the design-time “switch” is handled purely within the CollectionViewSource, where the Source is set differently depending on what mode we are in. Note that even though the CollectionViewSource is a resource, it will still correctly bind to our RuntimeBookingRowCollection.

Declaring the CollectionViewSource proxy within your Xaml will not suit all MVVM projects as sometimes you might want to define a CollectionView within your view model, but it worked in my case because the grouping was never going to change. For this project the grouping can be considered purely part of presentation so I am happy to declare it in Xaml, and as a bonus it works beautifully with design-time sample data!

I think this solution will work for Silverlight too, but I have not tested it yet.

d:DesignInstance in Depth

Update: I have contacted WPF “User education” team at Microsoft about the lack of documentation. The response was: “I’ve looked into this and there was some confusion around whether or not these were publicly exposed. Thanks for letting us know about this error. We are now working on getting these documented.”

There is currently no formal documentation for the DesignInstanceExtension (which you will see in XAML as d:DesignInstance).

The best two articles are by Unni and Karl but there are a few things they don’t cover.

This is what I have worked out by trial and error:

According to Intellisense DesignInstance has got 3 parameters: Type, IsDesignTimeCreatable and CreateList.

Type This is the type of the object for which the design-time data binding “shape” will be derived
IsDesignTimeCreatable (Defaults to false)

If this is true then a new instance of your type will be created at designtime. If you want data to actually appear in the designer you will need to make sure suitable properties are being set in your constructor. The best way to do this is to create a derived type of your model type, where you are free to set properties to default values without polluting your real types. If your model type implements an interface even better – you can create a design time model that way.

If this is false VS/Blend will use reflection to create a dummy type with the same shape as your specified Type. The problem with this is the dummy type will have no instance data in it thus you will not see anything in the designer. When this is false you are really only getting the benefit of assisted type-aware data binding. (If you need lots of sample data you are better off using the DesignData extension)

CreateList (Defaults to false)

If true the DesignInstance will actually be created as a list of the specified Type. From what I can tell this is the only way to specify your design instance as a collection (I briefly tried to pass a generic list as the Type parameter but could not get it to work, hence why I expect this parameter exists).

Note that DesignInstance and DesignData are mutually exclusive mark-up extensions. You cannot set both DesignInstance and DesignData extensions when setting your DataContext.

In general the main use of DesignInstance extension is to allow you to use the data binding tools within Blend and Visual Studio. It can give you some sample data if you set properties in your constructor.

To be able to design effectively you really need plentiful and varied sample data. For the best design experience you should consider using the DesignData extension – the drawbacks being the slightly increased upfront cost of creating a XAML file containing your sample data, and the increased complexity of refactoring the XAML whenever your classes change.

An Auto-Centering Canvas for WPF

If you try using WPF Canvas to plot objects in a 2d “scene”, you will hit a small problem. The Left and Top dependency properties dictate where the top left corner of your element is positioned. Not so good if you want to plot your elements at or over the coordinate position.

Here is a simple way to extend the Canvas such that Top and Left position your elements around their center.

    public class CenteringCanvas : Canvas
    {
        protected override Size ArrangeOverride(Size arrangeSize)
        {
            foreach (UIElement element in base.InternalChildren)
            {
                if (element == null)
                {
                    continue;
                }
                double x = 0.0;
                double y = 0.0;
                double left = GetLeft(element);
                if (!double.IsNaN(left))
                {
                    x = left - element.DesiredSize.Width/2;
                }
                
                double top = GetTop(element);
                if (!double.IsNaN(top))
                {
                    y = top - element.DesiredSize.Height/2;
                }
                
                element.Arrange(new Rect(new Point(x, y), element.DesiredSize));
            }
            return arrangeSize;
        }
    }

Of course don’t expect this code to work if you try setting the Right or Bottom properties.

Microsoft Surface development goes public

At PDC this year Microsoft announced that Surface development resources were going to be made publicly available. (Up until now it had been an “invitation only” system).

This is great news and means anyone can build or prototype Surface applications. The Surface SDK comes with a very good simulator. A table is still needed to evaluate performance and usability, but you can go a long way with just the simulator.

Microsoft Surface Simulator

Here is a copy & paste from a recent mail-out:

  • Surface Web site (http://www.surface.com)
  • MSDN (http://msdn.microsoft.com)
  • TechNet (http://technet.microsoft.com)
  • Microsoft Download center (http://www.microsoft.com/downloads)
    • A new product category for all Surface downloads, including the Surface SDK Workstation Edition, applications, documentation, and any software fixes.
  • Microsoft Support (http://support.microsoft.com)
  • WCF Data Services vs WCF RIA Services

    I’ve been having trouble finding a straight forward comparison of these two technologies. On the surface they appear to be solving similar, if not the same problems.

    Make no mistake – the message coming from Microsoft is not clear or consistent – which probably explains the confusion. I suspect the relationship between these two products is still being “discovered” by MS.

    Anyway, in this bliki I will try to sum up my findings as to the differences between them as I figure them out.

    WCF (ADO.NET) Data Services

    WCF (.NET) RIA Services

    Expose data model as RESTful web service Prescriptive approach to n-tier app development
    Cross platform interoperation as a goal
    – “Unlock data silos”
    – Out-of-box support from future MS products such as SQL2008 R2, Azure, Excel 2010, SharePoint 2010
    Designed specifically for end-to-end Silverlight & ASP.NET solutions
    – Some technology proprietary to Silverlight (no WPF support)
    – Use ASP.NET Authentication/Roles across SL and ASP.NET
    – ASP.NET/AJAX can also access service layer
    Loosely coupled clients and servers Client & server are designed and deployed together
    Service layer exposes “raw” data sources Opportunity to easily add business logic into service layer
    – Encourage “domain” concepts
    – Strong validation framework
    – Offline / Sync enabled
    Service can be consumed from .NET, Silverlight, AJAX, PHP and Java (libraries available) Service can be consumed easily from SL, AJAX, WebForms
    Service’s data source must:
    – Expose at least one IQueryable property
    – Implement IUpdateable if you desire updates
    Service exposes domain objects via convention:
    – IQueryable GetX
    – UpdateX/InsertX/DeleteX
    No design time experience yet (??) Design time experience with data sources, drag drop etc
    – OData for all clients
    – Within OData, multiple formats supported (JSON, XML etc)
    – SOAP (binary) for SL clients
    – JSON for AJAX clients
    – SOAP (XML) for other clients
    Discoverable (?) Non-discoverable
    Hosted as WCF Service (.svc) Old version hosted in custom web handler (.axd).
    New version is WCF service.
    Standardized on OData protocol Will “support” OData
    More mature – public for at least 2 years, formerly “Project Astoria” Less mature – public for 6 months


    Common features

    • Based on WCF
    • Use a RESTful architecture
    • Can be used to expose any data source (sql, xml, poco/objects etc.)
    • Client side libraries provide ability to query using LINQ

    General

    • Currently they do not share much (any?) technology / code
    • RIA Services is not based on top of Data Services
    • RIA Services & Data Services will “align”
    • OData eventually pushed down into WCF stack

    Your opinions are welcome!

    References

    http://blogs.msdn.com/brada/archive/2009/03/19/what-is-net-ria-services.aspx

    http://mschannel9.vo.msecnd.net/o9/mix/09/pptx/t36f.pptx

    http://blogs.msdn.com/endpoint/archive/2009/11/18/the-wcf-services-ecosystem.aspx

    http://www.douglaspurdy.com/2009/11/20/on-odata-open-data-protocol/

    http://msdn.microsoft.com/en-us/data/ee844254.aspx

    http://blogs.msdn.com/saurabh/archive/2009/11/23/understanding-the-wcf-in-wcf-ria-services.aspx