I'm a fairly novice programmer, and making a Windows Store App. I have an object that contains an ObservableCollection(Of T)
that I want to group for display in a ListView
. Using LINQ to return a set of grouped items seems like it would be the best and easiest choice. Every piece of documentation I could find says that Group By returns IEnumerable(Of IGrouping(Of TKey, TItem))
and you set CollectionViewSource.IsSourceGrouped
to True, bind to the CVS and it should all work perfectly. Right?
Not so much.
I have a class that contains
Public Property Items As ObservableCollection(Of Item)
Public ReadOnly Property GroupedItems As IEnumerable
Get
' Return grouped items
End Get
End Property
And in the XAML for the page, where GroupedItems
is set as the Page
's DataContext
in code-behind:
<Page.Resources>
<CollectionViewSource x:Name="GroupedItems" Source="{Binding}" IsSourceGrouped="True" />
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ListView ItemsSource="{Binding Source={StaticResource GroupedItems}}">
<ListView.GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<!-- Template -->
</DataTemplate>
</GroupStyle.HeaderTemplate>
</ListView.GroupStyle>
<ListView.ItemTemplate>
<DataTemplate>
<!-- Template -->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Now, if I bind the ListView
to the ObservableCollection(Of Item)
directly, the ListView
renders all the items as expected, following the ItemTemplate
. But when it is bound to the supposedly-grouped CollectionViewSource
, the ListView
renders the groups according to the HeaderTemplate
, but it doesn't render any of the items within the group.
I've inspected the results of the LINQ logic:
Dim x = From i As Item In Items
Group i By Key = i.SubItem Into Group
And x
has a Key
property and a Group
property, though it is some kind of IEnumerable(Of anonymous) type rather than an IEnumerable(Of IGrouping(Of TKey, TItem))
.
So what am I doing wrong here? Is there another caveat to the VB.NET implementation of LINQ that I'm missing? Is there a property I'm forgetting to set? What is the right way to do this?
I found a solution, though I don't know that it is the ideal solution. Because the result of the LINQ query places the items in the Group
property of its anonymous type, CollectionViewSource
needs to know that. So by adding ItemsPath="Group"
to the XAML defining the CollectionViewSource
, it now displays both the group headers and the containing items.