Specifying collections as data source in Design view

One of the nicest design-time features of WPF and Silverlight is the ability to specify data in design time, allowing your designers to work with controls already filled with data without starting the whole application. However, there's not much hints on how to work with it for slightly more complex and non-trivial scenarios, for example when binding to a collection.

Let's suppose that in our Silverlight application we have a ListBox with an ItemSource and SelectedItem binding, which is quite an ordinary situation if you are using MVVM pattern for your application.

<ListBox ItemsSource="{Binding TestCollection}" SelectedItem="{Binding SelectedObject,Mode=TwoWay}"/>

Now, how would you specify a sample collection instead of TestCollection in design-time? MSDN help doesn't give you a clear answer on that. You can redefine DataContext, but not the binding itself. However, it's possible to change the whole context, as it was shown for example in Paul Betts' post. The trick is to put your ListBox inside some kind of container, then redefine DataContext in it to an Expression Blend sample data:

<Border DataContext="{Binding TestCollection}" d:DataContext="{Binding Collection, Source={StaticResource SampleTestObjects}}">
                    <ListBox ItemsSource="{Binding}" SelectedItem="{Binding SelectedObject,Mode=TwoWay}">
</Border>

But this trick will completely break the SelectedItem binding and other bindings of ListBox, as they expect completely different object in DataContext. This problem is also avoidable: ElementName binding will come to your help. You may place your container+ListBox inside another named container, then bind to it in your SelectedItem bindings:

<StackPanel Orientation="Horizontal" x:Name="dataContextRoot">
      <Border DataContext="{Binding TestCollection}" d:DataContext="{Binding Collection, Source={StaticResource SampleTestObjects}}">
               <ListBox ItemsSource="{Binding}" SelectedItem="{Binding ElementName=dataContextRoot,Path=DataContext.SelectedObject,Mode=TwoWay}">
      </Border>
</StackPanel>

However, all these workarounds are not self-explanatory, and introduce some complications in your XAML that are not easily understandable by a programmer, all the more by a designer. So without further discussion, let's introduce the right decision instead: use intermediate CollectionViewSource as your binding target:

<UserControl.Resources>
        <CollectionViewSource x:Key="ItemModelsViewSource"
            d:DesignSource="{Binding Collection, Source={StaticResource SampleTestObjects}}"
            Source="{Binding TestCollection}" />
</UserControl.Resources>
...
<ListBox ItemsSource="{Binding Source={StaticResource ItemModelsViewSource}}" SelectedItem="{Binding SelectedObject,Mode=TwoWay}"/>

Unlike ListBox, CollectionViewSource's Source could be redefined in design-time, which greatly simplifies things in our case. No more unnatural containers, introduced only for workaround: binding ListBox through CollectionViewSource is a good thing, as it allows to handle things like filtering and sorting directly in XAML, so it may be useful later. Besides, binding through ElementName to parent's DataContext sometimes behaves glitchy. You won't encounter this kind of problems with CollectionViewSource.

I described two possible ways to specify collection as data source visible both in Visual Studio 2010 Design view and in Expression Blend. As you see, with a little extra effort you can make your ListBox very designer-friendly!

AttachmentSize
designitemssourcedemo.zip10.68 KB

Comments

Re: binding to QueryString

I'm not sure if I understood your remark. Are you trying to bind on QueryString's parameters? In this case I would recommend to use intermediate model, and in design time use another model instead of this one. See also:

http://forums.silverlight.net/forums/p/120481/271691.aspx
http://www.scip.be/index.php?Page=ArticlesNET32#DesignTimeData