DesignTime data not showing in Blend when bound against CollectionViewSource
Asked Answered
R

3

15

I have a datatemplate for a viewmodel where an itemscontrol is bound against a CollectionViewSource (to enable sorting in xaml).

<DataTemplate x:Key="equipmentDataTemplate">
    <Viewbox>
        <Viewbox.Resources>
            <CollectionViewSource x:Key="viewSource" Source="{Binding Modules}">
                <CollectionViewSource.SortDescriptions>
                    <scm:SortDescription PropertyName="ID" Direction="Ascending"/>
                </CollectionViewSource.SortDescriptions>
            </CollectionViewSource>
        </Viewbox.Resources>
        <ItemsControl ItemsSource="{Binding Source={StaticResource viewSource}}" 
                      Height="{DynamicResource equipmentHeight}" 
                      ItemTemplate="{StaticResource moduleDataTemplate}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Viewbox>
</DataTemplate>

I have also setup the UserControl where all of this is defined to provide designtime data

d:DataContext="{x:Static vm:DesignTimeHelper.Equipment}">

This is basically a static property that gives me an EquipmentViewModel that has a list of ModuleViewModels (Equipment.Modules). Now as long as I bind to the CollectionViewSource the designtime data does not show up in blend 3. When I bind to the ViewModel collection directly

<ItemsControl ItemsSource="{Binding Modules}"

I can see the designtime data. Any idea what I could do?

Repugnant answered 19/9, 2009 at 6:35 Comment(1)
Have the same problem exactly. Binding against a List<T> property is fine, but as soon as I bind against a CollectionView bound to that property, all data disappears.Doorpost
U
7

Been there done that (now at least) :)

This is the solution I've found. The trick is to override the source for the CollectionViewSource designtime. I use the d:DesignSource property to use another static resource designtime:

<Window.Resources>
    <CollectionViewSource x:Key="ViewSource"
            Source="{Binding ModelProperty}"
            d:DesignSource="{{x:Static MyProg:DesignTimeData.MyList}">
        <!-- Contents -->
    </CollectionViewSource>
</Window.Resources>
    
<!-- No change to the using class -->
<ListBox ItemsSource="{Binding Source={StaticResource ViewSource}}">
        
</ListBox>
Undersize answered 21/4, 2011 at 9:17 Comment(0)
C
0
  1. I am not sure x:Static is supposed to work in d:DataContext, I think only d:DesignInstance or d:DesignData could.
  2. Did you test the design time data and sure that indeed filled with data?
  3. Try specifying the d:IsDesignTimeCreatable=True property in the d:DesignInstance.
  4. Although this is Silverlight specific I am sure it might give you some hint.

It should generally look like this:

d:DataContext="{d:DesignInstance Type=vm:EquipmentViewModel, IsDesignTimeCreatable=True}"

You could use the same ViewModel for both runtime and designtime, make a IsInDesignTime property in you ViewModelBase and return data appropriately.
Example:

private static bool? _isInDesignMode;
public static bool IsInDesignModeStatic
{
    get
    {
        if (!_isInDesignMode.HasValue)
        {
            var prop = DesignerProperties.IsInDesignModeProperty;
            _isInDesignMode
                = (bool)DependencyPropertyDescriptor
                .FromProperty(prop, typeof(FrameworkElement))
                .Metadata.DefaultValue;
        }

        return _isInDesignMode.Value;
    }
}

Note: I would encourage you to use StaticResources (rather than DynamicResources) for templates or styles that are not meant to change at runtime. Read this for more info.

Collapse answered 18/3, 2011 at 3:50 Comment(0)
G
0

Not sure if this is still relevant... recently had a similar issue - I'm still somewhere on the WPF learning curve, just not quite sure where...

Anyways, here's the scenario: I would create an object of type ObservableCollection somewhere in my local namespace (to keep things simple), for example..

public class NodesCollection : ObservableCollection<Nodes> { }

Then from Blend/Xaml, I can easily "Create Object Data Source" (from Data tools panel) and find NodesCollection is shown and can be selected.

Next, Blend will create a local resource near the top of the Xaml file, similar to:

<local:NodesCollection x:Key="NodesCollectionDataSource" d:IsDataSource="True" />

With this, you can easily bind the ItemsSource property of a listbox to the datasource we have just created. For example, right-click on your listbox from "Objects and Timeline" tools panel and select "Data bind ItemsSource to Data.." In the popup dialog box, you will easily see NodesCollectionDataSource is available and can be used.

However here comes the issues I had to resolve...

In some books I'm reading at the moment, they talk about creating a CollectionViewSource in Xaml that can be used for sorting/grouping/filtering/navigating its underlying data source.

First issue, I can't find CollectionViewSource anywhere in Blend; so the only option is to create the tag in Xaml manually.

Simply type <CollectionViewSource x:Key="cvsNodes" /> within the Resources block (Xaml) and from there, you can modify additional properties using the Blend GUI; for example setting the underlying Source property and additional Sort and Group Descriptors (found under the Resources tools panel).

Now comes the part where we want to bind the ListBox's ItemsSource property to the CollectionViewSource. However you wont be able to find that item using the Blend GUI. Therefore you must type the binding value manually. For example:

<ListBox x:Name=.. ItemsSource="{Binding Source={DynamicResource cvsNodes}}".. />

This works. But to make it even easier, we need to go back to the original CollectionViewSource resource element in Xaml and add an additional attribute:

<CollectionViewSource x:Key="cvsNodes" Source=... d:IsDataSource="True"

The d:IsDataSource="True" does the trick of having Blend GUI recognize that resource as available to be used.

Now if we go back to the ListBox's ItemsSource property from the Properties tools panel, we should be able to select cvsNodes from the list of available Data sources.

I hope this helps anyone who may have come to the same conclusion as me, which is that Blend and the underlying Xaml technology isn't completely synchronized; and that Blend is at best a tool for generating the Xaml, not a replacement for learning the Xaml language.

Gutbucket answered 10/4, 2013 at 3:1 Comment(1)
Also just to help answer the original question; Yes, this does allow Blend to show sample data during development. All you need to do is populate some sample data within the constructor of your ObjectCollection class - in my case, that would be the ctor to NodesCollectionGutbucket

© 2022 - 2024 — McMap. All rights reserved.