0
votes

I have a ListBox populated by grouped data with a header and child items beneath it - I want to customize the control such that each group header is an Expander (initially closed) and expanding it would reveal the items for that group underneath it

I'm still new to WPF so how would I do this? Do I need to implement data templates for the HeaderTemplate of the GroupStyle (would this contain an ItemsPresenter here?) and the ItemTemplate or would I need to create a completely new ControlTemplate in addition to the two data templates?

Also, would using an Expander for headers disable the item virtualization feature of the ListBox? If so what can I do to ensure this doesn't happen? If I put a VirtualizingStackPanel in the Expander content, would that mitigate this or is this unecessary?

My grouping is very simple and simply a flat collection on one field:

ICollectionView collegeView = new ListCollectionView(playerDatabase);
collegeView.GroupDescriptions.Add(new PropertyGroupDescription("CollegeName"));
collegeView.SortDescriptions.Add(new SortDescription("CollegeName", ListSortDirection.Ascending));
collegeView.SortDescriptions.Add(new SortDescription("FirstName", ListSortDirection.Ascending));
lstCollege.ItemsSource = collegeView;

UPDATE This is what I have tried so far:

<ListBox x:Name="lstCollege" IsSynchronizedWithCurrentItem="True">
<ListBox.GroupStyle>
    <GroupStyle>
        <GroupStyle.HeaderTemplate>
            <DataTemplate>
                <Border Background="Blue" CornerRadius="5">
                     <Expander Header="{Binding Path=Name}" FontWeight="Bold" Foreground="White" Padding="3">
                         <ItemsPresenter />
                     </Expander>
                </Border>
            </DataTemplate>
        </GroupStyle.HeaderTemplate>
    </GroupStyle>
</ListBox.GroupStyle>

<ListBox.ItemTemplate>
    <DataTemplate>
        <StackPanel Orientation="Vertical">
            <TextBlock>
                <TextBlock.Text>
                    <MultiBinding StringFormat="{}{0} {1}">
                        <Binding Path="FirstName" />
                        <Binding Path="LastName" />
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </StackPanel>
    </DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Unfortunately, what this renders is an Expander for each group, however the items are not rendered inside of it - they are rendered outside the group item and the Expander is empty

I think the reason this is happening is because a GroupItem is rendered separately from the ListItem (or whatever it's called) and therefore the ListViewItem is not contained inside each GroupItem ...I think the way the ListBox renders it is GroupItem, ListItem, ListItem, ListItem, GroupItem, ListItem etc.

How would I change the control so that each GroupItem can also contain a set of ListItems ?

1
Posting some code would help - how exactly are you doing the grouping? Is your ItemsSource flat and the headers & items are all in the same list? Or are the headers complex types with a property that defines the children? I don't believe using an Expander in your DataTemplate will automatically prevent virtualization.Brian S
Posted the sample code. The emphasis of my question is more towards what is the minimum I need to implement to get the behavior I'm describing - can I just define the DataTemplates or do I need to define an entire ControlTemplate? If I need to create a ControlTemplate, what's the minimum I need to do to preserve the ListBox functionality?blue18hutthutt
Ok, the fact that you're using the ICollectionView explains how you're doing the grouping. See my answer below.Brian S

1 Answers

2
votes

You should be able to create a GroupStyle and specifically use the ContainerStyle to define groups that are collapsible using an Expander. This doesn't require a DataTemplate or a ControlTemplate as it is specific to the grouping functionality. Take a look at the 'GroupStyle.ContainerStyle' property on MSDN, and this other answer also provides an example.