Wpf 如何通过物理滚动在列表框中滚动到下一个逻辑页
我有一个列表框,它必须有CanContentScroll==false,因为我需要能够平滑地滚动它。这将启用物理滚动 我还想逐页滚动列表框,但是如果我在listbox internal ScrollViewer上调用PageDown方法,第一行将被剪切,因为列表框高度不是行高度的倍数 我希望第一行始终完全可见,就像使用逻辑滚动时一样Wpf 如何通过物理滚动在列表框中滚动到下一个逻辑页,wpf,listbox,scroll,Wpf,Listbox,Scroll,我有一个列表框,它必须有CanContentScroll==false,因为我需要能够平滑地滚动它。这将启用物理滚动 我还想逐页滚动列表框,但是如果我在listbox internal ScrollViewer上调用PageDown方法,第一行将被剪切,因为列表框高度不是行高度的倍数 我希望第一行始终完全可见,就像使用逻辑滚动时一样 有人能告诉我怎么做吗?如果你将“新页面”的顶部项目滚动到视图中,这会达到你想要的效果吗? 看 如果向下滚动,然后用鼠标选择上方可见的容器,则非虚拟化项控件(Scro
有人能告诉我怎么做吗?如果你将“新页面”的顶部项目滚动到视图中,这会达到你想要的效果吗?
看 如果向下滚动,然后用鼠标选择上方可见的容器,则非虚拟化
项控件(ScrollViewer.CanContentScroll=“False”
)的效果与虚拟化控件相同。这也可以在代码中完成
当CanContentScroll
设置为false时,虚拟化将关闭,因此将始终生成所有容器。要获得顶部可见的容器,我们可以从顶部迭代容器,直到到达ScrollViewer
的VerticalOffset
。一旦我们得到了它,我们就可以简单地在它上面调用BringIntoView
,它将在顶部很好地对齐,就像使用虚拟化一样
范例
为了仅在您想要调用PageDown
时实现此效果,例如,在按钮单击中,您可以为ListBox
创建一个名为logicalpage down
的扩展方法
listBox.LogicalPageDown();
ListBoxExtensions
我认为该项目将显示在列表框的底部,而不是顶部。另外,我也不知道如何识别该项目。@Zmaster:忘记了在查找容器的相对位置时可能涉及到边距
等。在我决定使用ScrollToOffset()时更新了我的答案,方法是在假设每个项目都具有相同高度的情况下计算目标偏移量(这是我的情况)。它比迭代项目更有效。另一方面,您的解决方案也适用于不同高度的项目,因此我接受它作为答案。
private void listBox_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ItemsControl itemsControl = sender as ItemsControl;
ScrollViewer scrollViewer = e.OriginalSource as ScrollViewer;
FrameworkElement lastElement = null;
foreach (object obj in itemsControl.Items)
{
FrameworkElement element = itemsControl.ItemContainerGenerator.ContainerFromItem(obj) as FrameworkElement;
double offset = element.TransformToAncestor(scrollViewer).Transform(new Point(0, 0)).Y + scrollViewer.VerticalOffset;
if (offset > e.VerticalOffset)
{
if (lastElement != null)
lastElement.BringIntoView();
break;
}
lastElement = element;
}
}
listBox.LogicalPageDown();
public static class ListBoxExtensions
{
public static void LogicalPageDown(this ListBox listBox)
{
ScrollViewer scrollViewer = VisualTreeHelpers.GetVisualChild<ScrollViewer>(listBox);
ScrollChangedEventHandler scrollChangedHandler = null;
scrollChangedHandler = (object sender2, ScrollChangedEventArgs e2) =>
{
scrollViewer.ScrollChanged -= scrollChangedHandler;
FrameworkElement lastElement = null;
foreach (object obj in listBox.Items)
{
FrameworkElement element = listBox.ItemContainerGenerator.ContainerFromItem(obj) as FrameworkElement;
double offset = element.TransformToAncestor(scrollViewer).Transform(new Point(0, 0)).Y + scrollViewer.VerticalOffset;
if (offset > scrollViewer.VerticalOffset)
{
if (lastElement != null)
lastElement.BringIntoView();
break;
}
lastElement = element;
}
};
scrollViewer.ScrollChanged += scrollChangedHandler;
scrollViewer.PageDown();
}
}
public static T GetVisualChild<T>(DependencyObject parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}