Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vertical Separator in ListBox Group

Tags:

c#

wpf

listbox

I have a ListBox where I did the grouping based on a property like this :

CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(listbox.ItemsSource);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("CurrentDate");
view.GroupDescriptions.Add(groupDescription);

And after grouping I want to add a vertical separator between the groups and I wrote a code like this:

<ListBox.GroupStyle>
    <GroupStyle>
        <GroupStyle.HeaderTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
                    <TextBlock Text="{Binding Path=Name}"
                               FontWeight="Bold"/>
                </StackPanel>
            </DataTemplate>
        </GroupStyle.HeaderTemplate>
        <GroupStyle.Panel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </GroupStyle.Panel>
    </GroupStyle>
</ListBox.GroupStyle>

But it's appearing like this:

enter image description here

Whereas I want a separator to go down totally but when I am trying to increase the height of the separator the items goes down along with that.

like image 562
Vivek Saurav Avatar asked Jan 10 '17 12:01

Vivek Saurav


1 Answers

Diagnosis

When you group items in a ListBox using CollectionView + GroupStyle what happens is the ListBox displays a list of GroupItem controls, each representing a group of items. A GroupItem basically consists of a ContentPresenter (for presenting the header) and an ItemsPresenter (for presenting grouped items) put in a StackPanel.

When you specify GroupStyle.HeaderTemplate it will be used as ContentTemplate for the mentioned ContentPresenter. So if you increase the height of the Separator it will still be contained in the ContentPresenter causing it to grow vertically, and the items will still be stacked below it - hence your result.

Solution

What you need to do to achieve your goal is to re-template the GroupItem so that the Separator is displayed alongside the ContentPresenter and ItemsPresenter, and then wire it using GroupStyle.ContainerStyle. For convenience, let's put it in ListBox.Resources dictionary:

<ListBox (...)>
    <ListBox.Resources>
         <ControlTemplate x:Key="GroupItemTemplate" TargetType="{x:Type GroupItem}">
            <DockPanel>
                <Separator DockPanel.Dock="Left"
                           Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
                <StackPanel>
                    <ContentPresenter /><!-- This will be automatically wired -->
                    <ItemsPresenter Margin="5,0,0,0" /><!-- So will this -->
                </StackPanel>
            </DockPanel>
        </ControlTemplate>
    </ListBox.Resource>
    <ListBox.GroupStyle>
        <GroupStyle>
             <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" />
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
            <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                    <Setter Property="Template"
                            Value="{StaticResource GroupItemTemplate}" />
                </Style>
            </GroupStyle.ContainerStyle>
            (...)
        </GroupStyle>
    </ListBox.GroupStyle>
    (...)
</ListBox>

Notice that I removed the separator from the header template.

Here are possible outcomes you may want to get (I put a blue border around the ListBox to distinguish #3 and #4):

enter image description here

The code excerpt I provided will by default give you #1 (all separators are stretched vertically across the whole ListBox).

To achieve #2 (separators stretch down only to the last item of the corresponding group) you should add <Setter Property="VerticalAlignment" Value="Top" /> to the GroupStyle.ContainerStyle. Alternatively you could put it on the DockPanel inside the GroupItem template instead.

To get #3 (separators stretch to the height of the largest group) you should add VerticalAlignment="Top" to the panel inside the GroupStyle.Panel (the VirtualizingStackPanel in your case).

And finally #4 (the ListBox itself is restricted to the size of the largest group) can be achievied by putting VerticalAlignment="Top" on the ListBox itself.

like image 142
Grx70 Avatar answered Oct 13 '22 12:10

Grx70