I have a datatemplate for a viewmodel where an itemscontrol is bound against a CollectionViewSource (to enable sorting in xaml).
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.
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.Resource>
<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>
x:Static
is supposed to work in d:DataContext
, I think only d:DesignInstance or d:DesignData
could.d:IsDesignTimeCreatable=True
property in the d:DesignInstance
.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.