Using CollectionViewSource with HierarchicalDataTemplate
How could you use a CollectionViewSource (to provide sorting behavior) in conjunction with the HierarchicalDataTemplate ItemsSource?
So, given the code below, how can I apply sorting by children at each level of the hierarchy?
<HierarchicalDataTemplate DataType="{x:Type l:CommandGroup}"
ItemsSource="{Binding Children}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}"
BasedOn="{StaticResource {x:Type MenuItem}}">
<Setter Property="Command"
Value="{Binding Command}" />
<Setter Property="CommandParameter"
Value="{Binding}" />
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
I thought I could do the following, but it splits the descendants into show and also throws the following binding error.
<HierarchicalDataTemplate DataType="{x:Type l:CommandGroup}">
<HierarchicalDataTemplate.ItemsSource>
<Binding>
<Binding.Source>
<CollectionViewSource Source="{Binding Children}" />
</Binding.Source>
</Binding>
</HierarchicalDataTemplate.ItemsSource>
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}"
BasedOn="{StaticResource {x:Type MenuItem}}">
<Setter Property="Command"
Value="{Binding Command}" />
<Setter Property="CommandParameter"
Value="{Binding}" />
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Children; DataItem=null; target element is 'CollectionViewSource' (HashCode=5114324); target property is 'Source' (type 'Object')
Edit: I ended up with the following: hope this helps someone else
<Window.Resources>
<l:SortedCollectionViewSource x:Key="SortedCollectionViewSource" Property="Name"/>
</Window.Resources>
<Window.ContextMenu>
<ContextMenu>
<MenuItem Header="Add new item..."
ItemsSource="{Binding AddNewItem.Children, Converter={StaticResource SortedCollectionViewSource}}">
<MenuItem.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type l:CommandGroup}"
ItemsSource="{Binding Children, Converter={StaticResource SortedCollectionViewSource}}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}"
BasedOn="{StaticResource {x:Type MenuItem}}">
<Setter Property="Command"
Value="{Binding Command}" />
<Setter Property="CommandParameter"
Value="{Binding}" />
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
</ContextMenu>
</Window.ContextMenu>
public class SortedCollectionViewSource : IValueConverter
{
public string Property { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var cvs = new CollectionViewSource() { Source = value };
cvs.SortDescriptions.Add(new SortDescription(Property, ListSortDirection.Ascending));
return cvs.View;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
source to share
as the error says it is CollectionViewSource
not an element FrameworkElement
, so the binding will not be able to resolve the property values.
as a solution you can have a read-only property in the viewmodel for it and bind it to HierarchicalDataTemplate.ItemsSource
eg,
public CollectionViewSource MyCollectionView
{
get { return new CollectionViewSource() { Source = Children }; }
}
and bind it like
<HierarchicalDataTemplate DataType="{x:Type l:CommandGroup}"
ItemsSource="{Binding MyCollectionView}">
CollectionViewSource is a xaml that can usually bind to static / dynamic resources or static properties, and other binding always has problem as CollectionViewSource does not pass DataContext
as a try you can try but not sure if this works
<HierarchicalDataTemplate x:name="hTemplate" DataType="{x:Type l:CommandGroup}">
<HierarchicalDataTemplate.ItemsSource>
<CollectionViewSource Source="{Binding DataContext.Children,ElementName=hTemplate}" />
as above, you can try this, can it work if CollectionViewSource can resolve correct original collection
<HierarchicalDataTemplate x:name="hTemplate" DataType="{x:Type l:CommandGroup}">
<HierarchicalDataTemplate.ItemsSource>
<Binding>
<Binding.Source>
<CollectionViewSource Source="{Binding DataContext.Children,ElementName=hTemplate}" />
source to share