0

我有一个使用 VirtualizingStackPanel 的 Itemscontrol 来显示一个巨大的(并且不断增长的)项目列表:

<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>

虚拟化就像一个魅力,但我无法正确管理滚动条。如果我尝试以编程方式(例如加载时)滚动到底部,就像我在非虚拟化 StackPanels 中所做的那样:

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

scrollviewer 尝试滚动到底部,但并没有完全这样做 - 它总是在“真实”底部之前停止一点。这在某种程度上是有道理的,因为 VirtualizingStackPanels 使用滚动值来确定要渲染的项目,但这完全是我的磨难,最终用户无法接受。

如何滚动到“真实”底部?如果我想精确地向下滚动到某个项目的顶部位于视口的顶部(除非“真实”底部自然地太近),我该怎么办?

4

1 回答 1

2

这是因为内置的 ItemsControl 类不支持虚拟化。您可以尝试使用默认情况下使用 UI 虚拟化的 ListBox。

如果您不想有选择行为,只需设置:

<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>

然后是这样的:

 lbCustom.ScrollIntoView(lbCustom.Items[lbCustom.Items.Count - 1]
于 2017-08-25T17:39:02.860 回答