我有一个带有一堆不规则大小的项目的ListView。当您滚动ListView时,最后一项的底部将最终位于控件的底部:您无法继续滚动。
如果最后一项小于控件,我希望最后一项的 top 能够滚动到控件的顶部(如果项目大于控件,我使用默认行为很好;在这种情况下,项目的顶部将滚动到ListView控件的顶部,满足我的设计)。 (这类似于Visual Studio Code中的行为,editor.scrollBeyondLastLine
设置为true)
我几乎让这个有效但但它并不存在。在我的尝试中,我将ListView
子类化,因此我可以覆盖PrepareContainerForItemOverride
。
然后我尝试为项目的下边距添加足够的额外空间,以便项目的顶部位于ListView的顶部。
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var lvi = element as ListViewItem;
if (lvi == null) { return; }
var currentIndex = this.Items.IndexOf(item);
if (currentIndex == (this.Items.Count - 1))
{
var sv = this.ScrollViewer();
lvi.Measure(new Size(sv.ViewportWidth, double.PositiveInfinity));
var slackSpace = sv.ViewportHeight - lvi.DesiredSize.Height;
if (slackSpace > 0)
{
lvi.Margin = new Thickness(lvi.Margin.Left, lvi.Margin.Top, lvi.Margin.Right, slackSpace + lvi.Margin.Bottom);
}
}
}
}
(在此代码中,this.ScrollViewer()
只是一个小的扩展方法,可以从任何ScrollViewer
中找出ListView
。我在这里尝试传递一些明智的东西到lvi.Measure
。)
这并不是很有效,因为DesiredSize.Height
的{{1}}最终比渲染ListViewItem
的{{1}}大一点(我不喜欢#39;不知道为什么)。
如果我知道Height
总是大于需要的话,我实际上可以将这种行为视为妥协......但我敢打赌,这并不是真的如此。
所以我显然需要插入渲染管道的不同部分来管理它。但我无法弄清楚在哪里。
我是否应该以某种方式对ListViewItem
DesiredSize.Height
进行子类化(因为我认为ListView's
实际上正在布置子ScrollViewer
控件?)?还有其他方法可以做到这一点吗?还是只是不可能?
答案 0 :(得分:1)
理想情况下,ScrollViewer
在安排孩子(在这种情况下是面板)后添加额外的间距将是ScrollViewer
的工作。仍然需要查看面板的最后一个子尺寸,以确切知道它应该添加多少空间。
但由于StackPanel
被封存,我不知道这是否真的可能。
另一个Hack,就是创建一个自定义ScrollViewer's
,我们可以在其中调整测量的高度,以便最后一个项目在顶部滚动。
底部的实际填充取决于ViewportHeight
public class BottomPaddedStackPanel: StackPanel
{
private ScrollViewer scroll = null;
public BottomPaddedStackPanel()
{
}
protected override Size MeasureOverride(Size availableSize)
{
if (scroll == null)
InitScrollViewerData();
Size panelSize = base.MeasureOverride(availableSize);
var lastChild = this.Children[this.Children.Count - 1];
if (scroll == null || scroll.ViewportHeight == 0)
return panelSize;
// add more space at the bottom to be able to scroll the last item at the top
if (lastChild.DesiredSize.Height < scroll.ViewportHeight)
panelSize.Height += scroll.ViewportHeight - lastChild.DesiredSize.Height;
return panelSize;
}
private void InitScrollViewerData()
{
var lastChild = this.Children[this.Children.Count - 1];
var lv = ItemsControl.ItemsControlFromItemContainer(lastChild);
Border rootBorder = VisualTreeHelper.GetChild(lv, 0) as Border;
scroll = rootBorder.Child as ScrollViewer;
scroll.SizeChanged += (o, ev) => InvalidateMeasure();
}
}
,因此多次通过度量布局步骤。
<ListView ItemsSource="{x:Bind Items}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<local:BottomPaddedStackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
设置为列表的布局面板:
path