带有 VirtualizingStackPanel 的 ItemsControl 中的精确滚动条控件
Accurate scrollbar control in an ItemsControl with a VirtualizingStackPanel
我有一个 Itemscontrol,它使用 VirtualizingStackPanel 来显示一个巨大的(并且还在不断增长的)项目列表:
<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>
虚拟化非常有效,但我无法正确管理滚动条。如果我尝试以编程方式(例如加载时)滚动到底部,就像我在非虚拟化 StackPanel 中所做的那样:
var scrollViewer = VisualTreeHelper.GetChild(ConversationItemsControl, 0) as ScrollViewer;
scrollViewer.ChangeView(null, double.MaxValue, 1f, true);
滚动查看器试图滚动到底部,但没有完全滚动到底部 - 它总是在 "real" 底部之前停止一点。这在某种程度上是有道理的,因为 VirtualizingStackPanels 使用滚动值来确定要呈现的项目,但这完全是磨练我的齿轮并且对于最终用户来说是不可接受的。
如何滚动到 "real" 底部?如果我想 精确 向下滚动到某个项目的顶部位于视口顶部(除非 "real" 底部太小),我该怎么办关闭,自然)?
这是因为内置的 ItemsControl class 不支持虚拟化。您可以尝试使用 ListBox,它默认使用 UI 虚拟化。
如果你不想有选择行为,只需设置:
<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]
我有一个 Itemscontrol,它使用 VirtualizingStackPanel 来显示一个巨大的(并且还在不断增长的)项目列表:
<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>
虚拟化非常有效,但我无法正确管理滚动条。如果我尝试以编程方式(例如加载时)滚动到底部,就像我在非虚拟化 StackPanel 中所做的那样:
var scrollViewer = VisualTreeHelper.GetChild(ConversationItemsControl, 0) as ScrollViewer;
scrollViewer.ChangeView(null, double.MaxValue, 1f, true);
滚动查看器试图滚动到底部,但没有完全滚动到底部 - 它总是在 "real" 底部之前停止一点。这在某种程度上是有道理的,因为 VirtualizingStackPanels 使用滚动值来确定要呈现的项目,但这完全是磨练我的齿轮并且对于最终用户来说是不可接受的。
如何滚动到 "real" 底部?如果我想 精确 向下滚动到某个项目的顶部位于视口顶部(除非 "real" 底部太小),我该怎么办关闭,自然)?
这是因为内置的 ItemsControl class 不支持虚拟化。您可以尝试使用 ListBox,它默认使用 UI 虚拟化。
如果你不想有选择行为,只需设置:
<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]