0

I have an Itemscontrol using a VirtualizingStackPanel to display a huge (and growing) list of items:

<ItemsControl Grid.Row="1" Name="ConversationItemsControl" VirtualizingStackPanel.VirtualizationMode="Recycling">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Vertical" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.Template>
        <ControlTemplate TargetType="ItemsControl">
            <ScrollViewer>
                <ItemsPresenter />
            </ScrollViewer>
        </ControlTemplate>
    </ItemsControl.Template>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <local:Message />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

The virtualization is working like a charm, but i cannot get the management of the scrollbar right. If I try to programmatically (e.g. on load) scroll to the bottom like i do in non-virtualized StackPanels:

var scrollViewer = VisualTreeHelper.GetChild(ConversationItemsControl, 0) as ScrollViewer;
scrollViewer.ChangeView(null, double.MaxValue, 1f, true);

the scrollviewer tries to scroll to the bottom, but does not do so completely - it always stops a bit before the "real" bottom. This makes sense in a way since VirtualizingStackPanels are using the scroll value to determine which items to render, but it is totally grinding my gears and unacceptable for end users.

How can I scroll to the "real" bottom? What do I have to do if i want to scroll exactly so far down that the top of a certain item is at the top of the viewport (unless the "real" bottom is too close, naturally)?

Benni
  • 1,030
  • 2
  • 11
  • 18

1 Answers1

2

This is because the built-in ItemsControl class doesn't support virtualization. You can try a ListBox instead, which uses UI virtualization by default.

If you don't want to have selection behaviour, just set:

<ListBox x:Name="lbCustom">
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <ContentPresenter/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>

and then something like:

 lbCustom.ScrollIntoView(lbCustom.Items[lbCustom.Items.Count - 1]
sTrenat
  • 1,029
  • 9
  • 13
  • Thanks! One minor thing: In my custom UserControl i am sometimes replacing the ItemsSource and scrolling to the bottom, but it is rather glitchy (scrolls too far down). Setting the ItemsSource to an empty list and calling UpdateLayout beforehand mitigates this, am i missing something? – Benni Aug 25 '17 at 18:59
  • I didn't got anything like this yet, so i don't know how it looks and how to help you with this issue. Your glitch can have similar source :d – sTrenat Aug 25 '17 at 19:10