WPF List View Grouping Scroll Offset with Headers

Viewed 232

I have an odd issue with a WPF listview:

Background

  • Using WPF ListView
  • Using Grid View to add columns
  • Virtualizing
  • Using 4 layers of groups to group the data into expanders in a hierarchical structure
  • Binding to CollectionViewSource defined in window.resources
  • Due to indentation of the data (the data is contained in expanders) the headers are offset from the column data so I use TranslateTransform to offset the headers by a small amount

Problem

Everything displays correctly and in the perfect hierarchical structure, however when I scroll to the right, there comes a point when the data keeps scrolling but the headers stop, which results in an offset between the headers and the data columns.

I am sure this has something to do with the way I am offsetting the headers, and the length of the headers compared to the data but I cant seem to find the reason for this problem.

List View Scrolled to just before the offset point

Image Scrolled to just before the offset point

List View Scrolled to the end

Image Scrolled to the end

Code

nb. I have omitted some style stuff as there is a limit on characters for answers here

<!--  The main grid  -->
                <ListView x:Name="DataGrid"
                          Margin="0"
                          Background="{StaticResource MainBackgroundBrush}"
                          BorderThickness="0"
                          Foreground="{StaticResource LightBackgroundBrush}"
                          ItemsSource="{Binding Source={StaticResource DataCollectionView}}"
                          ScrollViewer.IsDeferredScrollingEnabled="False"
                          SelectionMode="Single"
                          VirtualizingPanel.CacheLength="1,2"
                          VirtualizingStackPanel.IsContainerVirtualizable="True"
                          VirtualizingStackPanel.IsVirtualizing="True"
                          VirtualizingStackPanel.IsVirtualizingWhenGrouping="True"
                          VirtualizingStackPanel.ScrollUnit="Pixel"
                          VirtualizingStackPanel.VirtualizationMode="Recycling">
                    <!--  Some styles and resources exclusive to this list view  -->
                    <ListView.Resources>
                            <Setter Property="IsExpanded" Value="False" />
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type Expander}">
                                        <Border Background="{TemplateBinding Background}"
                                                BorderBrush="{TemplateBinding BorderBrush}"
                                                BorderThickness="{TemplateBinding BorderThickness}"
                                                SnapsToDevicePixels="true">
                                            <DockPanel>

                                                <ToggleButton x:Name="HeaderSite"
                                                              Width="600"
                                                              MinWidth="0"
                                                              MinHeight="0"
                                                              Margin="1"
                                                              Padding="{TemplateBinding Padding}"
                                                              HorizontalAlignment="Left"
                                                              VerticalAlignment="Center"
                                                              Background="{TemplateBinding Background}"
                                                              Content="{TemplateBinding Header}"
                                                              ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}"
                                                              DockPanel.Dock="Top"
                                                              FontFamily="{TemplateBinding FontFamily}"
                                                              FontSize="{TemplateBinding FontSize}"
                                                              FontStretch="{TemplateBinding FontStretch}"
                                                              FontStyle="{TemplateBinding FontStyle}"
                                                              FontWeight="{TemplateBinding FontWeight}"
                                                              Foreground="{TemplateBinding Foreground}"
                                                              IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                                                              Template="{StaticResource AnimatedExpanderButton}" />
                                                <ContentPresenter x:Name="ExpandSite"
                                                                  Margin="{TemplateBinding Padding}"
                                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                                  DockPanel.Dock="Bottom"
                                                                  Focusable="false"
                                                                  Visibility="Collapsed" />
                                            </DockPanel>
                                        </Border>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsExpanded" Value="true">
                                                <Setter TargetName="ExpandSite" Property="Visibility" Value="Visible" />
                                            </Trigger>
                                            <Trigger Property="ExpandDirection" Value="Up">
                                                <Setter TargetName="HeaderSite" Property="Background" Value="Red" />
                                                <Setter TargetName="ExpandSite" Property="DockPanel.Dock" Value="Top" />
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Name}" Value="Title">
                                    <Setter Property="IsEnabled" Value="False" />
                                    <Setter Property="IsExpanded" Value="True" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                        <!--  Styles the column headers  -->
                        <Style TargetType="{x:Type GridViewColumnHeader}">
                            <!--  Add the event handler for a right click on the header  -->
                            <EventSetter Event="MouseRightButtonUp" Handler="GridViewColumnHeader_MouseRightButtonUp" />
                            <Setter Property="Background" Value="{StaticResource GradientBrush}" />
                            <Setter Property="ClickMode" Value="Press" />
                            <Setter Property="FontSize" Value="12" />
                            <Setter Property="FontWeight" Value="Bold" />
                            <Setter Property="Foreground" Value="{StaticResource LightBackgroundBrush}" />
                            <Setter Property="Height" Value="30" />
                            <Setter Property="MinWidth" Value="20" />
                            <!--  Offset the column headers to match the column data as the expanders will have offset the data  -->
                            <Setter Property="RenderTransform">
                                <Setter.Value>
                                    <TranslateTransform X="13" />
                                </Setter.Value>
                            </Setter>
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
                                        <Border BorderBrush="Black" BorderThickness="1,0,0,1">
                                            <Grid Background="{TemplateBinding Background}">
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="*" />
                                                    <ColumnDefinition Width="Auto" />
                                                </Grid.ColumnDefinitions>
                                                <!--  The two column re sizers  -->
                                                <Thumb x:Name="PART_HeaderGripper"
                                                       Width="18"
                                                       Margin="0,0,-10,0"
                                                       HorizontalAlignment="Right"
                                                       Background="Black"
                                                       Cursor="SizeWE">
                                                    <Thumb.Template>
                                                        <ControlTemplate TargetType="{x:Type Thumb}">
                                                            <Border Padding="{TemplateBinding Padding}" Background="Transparent">
                                                                <Rectangle Width="1"
                                                                           HorizontalAlignment="Center"
                                                                           Fill="{TemplateBinding Background}" />
                                                            </Border>
                                                        </ControlTemplate>
                                                    </Thumb.Template>
                                                </Thumb>
                                                <!--  The main content of the header  -->
                                                <ContentPresenter Name="HeaderContent"
                                                                  Grid.Column="0"
                                                                  Margin="5"
                                                                  HorizontalAlignment="Center"
                                                                  VerticalAlignment="Center" />
                                            </Grid>
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ListView.Resources>
                    <!--  Templates each level  -->
                    <ListView.GroupStyle>
                        <!--  Style for groups at the top level. this level is equivalent to a single database  -->
                        <GroupStyle>
                            <GroupStyle.ContainerStyle>
                                <Style TargetType="{x:Type GroupItem}">
                                    <Setter Property="Margin" Value="0" />
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate TargetType="{x:Type GroupItem}">
                                                <Border Margin="1"
                                                        Background="{StaticResource FandFBrush}"
                                                        BorderBrush="Black"
                                                        BorderThickness="2"
                                                        CornerRadius="3">
                                                    <Expander Margin="0"
                                                              FontSize="12"
                                                              FontWeight="Bold"
                                                              Foreground="{StaticResource LightBackgroundBrush}"
                                                              Header="{Binding Name}"
                                                              IsExpanded="True">
                                                        <ItemsPresenter x:Name="IP"
                                                                        Margin="0"
                                                                        VirtualizingPanel.IsContainerVirtualizable="True"
                                                                        VirtualizingPanel.IsVirtualizing="True"
                                                                        VirtualizingPanel.IsVirtualizingWhenGrouping="True"
                                                                        VirtualizingPanel.ScrollUnit="Item"
                                                                        VirtualizingPanel.VirtualizationMode="Recycling" />
                                                    </Expander>
                                                </Border>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </GroupStyle.ContainerStyle>
                        </GroupStyle>
                        <!--  Style for groups at the second level. this level is equivalent to a single case  -->
                        <GroupStyle>
                            <GroupStyle.ContainerStyle>
                                <Style TargetType="{x:Type GroupItem}">
                                    <Setter Property="Margin" Value="0" />
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate TargetType="{x:Type GroupItem}">
                                                <Border Margin="0"
                                                        Background="{StaticResource MainBackgroundBrush}"
                                                        BorderBrush="Black"
                                                        BorderThickness="2"
                                                        CornerRadius="3">
                                                    <Expander Margin="0"
                                                              FontSize="12"
                                                              FontWeight="Bold"
                                                              Foreground="{StaticResource LightBackgroundBrush}"
                                                              Header="{Binding Name}"
                                                              IsExpanded="True">
                                                        <ItemsPresenter x:Name="IP"
                                                                        Margin="0"
                                                                        VirtualizingPanel.IsContainerVirtualizable="True"
                                                                        VirtualizingPanel.IsVirtualizing="True"
                                                                        VirtualizingPanel.IsVirtualizingWhenGrouping="True"
                                                                        VirtualizingPanel.ScrollUnit="Item"
                                                                        VirtualizingPanel.VirtualizationMode="Recycling" />
                                                    </Expander>
                                                </Border>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </GroupStyle.ContainerStyle>
                        </GroupStyle>
                        <!--  Style for groups at the third level. this level is equivalent to a single sample type  -->
                        <GroupStyle>
                            <GroupStyle.ContainerStyle>
                                <Style TargetType="{x:Type GroupItem}">
                                    <Setter Property="Margin" Value="0" />
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate TargetType="{x:Type GroupItem}">
                                                <Border Margin="1"
                                                        BorderBrush="Black"
                                                        BorderThickness="0"
                                                        CornerRadius="3">
                                                    <ItemsPresenter x:Name="IP"
                                                                    Margin="0"
                                                                    VirtualizingPanel.IsContainerVirtualizable="True"
                                                                    VirtualizingPanel.IsVirtualizing="True"
                                                                    VirtualizingPanel.IsVirtualizingWhenGrouping="True"
                                                                    VirtualizingPanel.ScrollUnit="Item"
                                                                    VirtualizingPanel.VirtualizationMode="Recycling" />
                                                </Border>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </GroupStyle.ContainerStyle>
                        </GroupStyle>
                        <!--  Style for groups at the fourth level. this level is equivalent to a single sample  -->
                        <GroupStyle>
                            <GroupStyle.ContainerStyle>
                                <Style TargetType="{x:Type GroupItem}">
                                    <Setter Property="Margin" Value="0" />
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate TargetType="{x:Type GroupItem}">
                                                <Border Margin="0,0,0,1"
                                                        Background="Transparent"
                                                        BorderBrush="Black"
                                                        BorderThickness="2,2,2,2"
                                                        CornerRadius="3,3,0,0"
                                                        Visibility="{Binding Items[0].Fragment.Sample.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
                                                    <Expander Margin="0"
                                                              FontSize="12"
                                                              FontWeight="Bold"
                                                              Foreground="Black"
                                                              IsExpanded="True">
                                                        <Border Grid.Row="0"
                                                                Margin="1,0,1,1"
                                                                Background="{StaticResource MainBackgroundBrush}"
                                                                BorderBrush="Black"
                                                                BorderThickness="2,1,2,2"
                                                                CornerRadius="2">
                                                            <Grid>
                                                                <Grid.RowDefinitions>
                                                                    <RowDefinition Height="*" />
                                                                    <RowDefinition Height="Auto" />
                                                                </Grid.RowDefinitions>
                                                                <!--  The measurements themselves  -->
                                                                <Border Grid.Row="0"
                                                                        Margin="0"
                                                                        Background="{StaticResource MainBackgroundBrush}"
                                                                        BorderBrush="Black"
                                                                        BorderThickness="0,0,0,1"
                                                                        CornerRadius="0">
                                                                    <ItemsPresenter x:Name="IP"
                                                                                    Margin="0"
                                                                                    VirtualizingPanel.IsContainerVirtualizable="True"
                                                                                    VirtualizingPanel.IsVirtualizing="True"
                                                                                    VirtualizingPanel.IsVirtualizingWhenGrouping="True"
                                                                                    VirtualizingPanel.ScrollUnit="Item"
                                                                                    VirtualizingPanel.VirtualizationMode="Recycling" />
                                                                </Border>   </Grid>
                                                        </Border>
                                                    </Expander>
                                                </Border>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </GroupStyle.ContainerStyle>
                        </GroupStyle>
                    </ListView.GroupStyle>
                </ListView>
0 Answers
Related