C# 是否可以在 WPF 列表视图中实现平滑滚动?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1033841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to implement smooth scroll in a WPF listview?
提问by Joan Venge
Is it possible to implement smooth scroll in a WPF listview
like how it works in Firefox?
When the Firefox browser contained all listview
items and you hold down the middle mouse button (but not release), and drag it, it should smoothly scroll the listview
items. When you release it should stop.
是否可以listview
像在 Firefox 中一样在 WPF 中实现平滑滚动?
当 Firefox 浏览器包含所有listview
项目并且您按住鼠标中键(但不释放)并拖动它时,它应该平滑地滚动listview
项目。当你释放它应该停止。
It looks like this is not possible in winforms, but I am wondering if it is available in WPF?
看起来这在 winforms 中是不可能的,但我想知道它是否在 WPF 中可用?
回答by Pop Catalin
You can achieve smooth scrolling but you lose item virtualisation, so basically you should use this technique only if you have few elements in the list:
您可以实现平滑滚动,但会丢失项目虚拟化,因此基本上只有当列表中的元素很少时才应该使用此技术:
Info here: Smooth scrolling on listbox
此处的信息:在列表框上平滑滚动
Have you tried setting:
ScrollViewer.CanContentScroll="False"
on the list box?
This way the scrolling is handled by the panel rather than the listBox... You lose virtualisation if you do that though so it could be slower if you have a lot of content.
您是否尝试过设置:
ScrollViewer.CanContentScroll="False"
在列表框中?
这样滚动是由面板而不是列表框处理的......如果你这样做,你会失去虚拟化,所以如果你有很多内容,它可能会变慢。
回答by Eddie
Try setting the ScrollViewer.CanContentScrollattached property to falseon the ListView. But like Pop Catalinsaid, you lose item virtualization, meaning all the items in the list get loaded and populated at once, not when a set of items are needed to be displayed - so if the list is huge, it could cause some memory and performance issues.
尝试在ListView上将ScrollViewer.CanContentScroll附加属性设置为false。但是就像Pop Catalin所说的那样,你失去了项目虚拟化,这意味着列表中的所有项目都会立即加载和填充,而不是在需要显示一组项目时 - 所以如果列表很大,它可能会导致一些内存和性能问题。
回答by rmoore
It is indeed possible to do what you're asking, though it will require a fair amount of custom code.
确实可以按照您的要求进行操作,尽管它需要大量的自定义代码。
Normally in WPF a ScrollViewer uses what is known as Logical Scrolling, which means it's going to scroll item by item instead of by an offset amount. The other answers cover some of the ways you can change the Logical Scrolling behavior into that of Physical Scrolling. The other way is to make use of the ScrollToVertialOffset and ScrollToHorizontalOffset methods exposed by both ScrollViwer and IScrollInfo.
通常在 WPF 中,ScrollViewer 使用所谓的逻辑滚动,这意味着它将逐项滚动而不是按偏移量滚动。其他答案涵盖了将逻辑滚动行为更改为物理滚动行为的一些方法。另一种方法是利用由 ScrollViwer 和 IScrollInfo 公开的 ScrollToVertialOffset 和 ScrollToHorizontalOffset 方法。
To implement the larger part, the scrolling when the mouse wheel is pressed, we will need to make use of the MouseDown and MouseMove events.
为了实现更大的部分,即按下鼠标滚轮时的滚动,我们需要使用 MouseDown 和 MouseMove 事件。
<ListView x:Name="uiListView"
Mouse.MouseDown="OnListViewMouseDown"
Mouse.MouseMove="OnListViewMouseMove"
ScrollViewer.CanContentScroll="False">
....
</ListView>
In the MouseDown, we are going to record the current mouse position, which we will use as a relative point to determine which direction we scroll in. In the mouse move, we are going to get the ScrollViwer component of the ListView and then Scroll it accordingly.
在 MouseDown 中,我们将记录当前的鼠标位置,我们将使用它作为相对点来确定我们向哪个方向滚动。在鼠标移动中,我们将获得 ListView 的 ScrollViwer 组件,然后滚动它因此。
private Point myMousePlacementPoint;
private void OnListViewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.MiddleButton == MouseButtonState.Pressed)
{
myMousePlacementPoint = this.PointToScreen(Mouse.GetPosition(this));
}
}
private void OnListViewMouseMove(object sender, MouseEventArgs e)
{
ScrollViewer scrollViewer = ScrollHelper.GetScrollViewer(uiListView) as ScrollViewer;
if (e.MiddleButton == MouseButtonState.Pressed)
{
var currentPoint = this.PointToScreen(Mouse.GetPosition(this));
if (currentPoint.Y < myMousePlacementPoint.Y)
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - 3);
}
else if (currentPoint.Y > myMousePlacementPoint.Y)
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + 3);
}
if (currentPoint.X < myMousePlacementPoint.X)
{
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - 3);
}
else if (currentPoint.X > myMousePlacementPoint.X)
{
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + 3);
}
}
}
public static DependencyObject GetScrollViewer(DependencyObject o)
{
// Return the DependencyObject if it is a ScrollViewer
if (o is ScrollViewer)
{ return o; }
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
{
var child = VisualTreeHelper.GetChild(o, i);
var result = GetScrollViewer(child);
if (result == null)
{
continue;
}
else
{
return result;
}
}
return null;
}
There's some areas it's lacking as it's just a proof of concept but it should definitely get you started in the right direction. To have it constantly scroll once the mouse is moved away from the initial MouseDown point, the scrolling logic could go into a DispatcherTimer or something similar.
它缺少一些领域,因为它只是一个概念证明,但它绝对应该让您朝着正确的方向开始。一旦鼠标从初始的 MouseDown 点移开,要让它不断滚动,滚动逻辑可以进入 DispatcherTimer 或类似的东西。
回答by Nitron
try setting the listview's height as auto and wrapping it in a scroll viewer.
尝试将列表视图的高度设置为自动并将其包装在滚动查看器中。
<ScrollViewer IsTabStop="True" VerticalScrollBarVisibility="Auto">
<ListView></ListView>
</ScrollViewer>
Don't forget to mention the height of ScrollViewer Hope this helps....
不要忘记提及 ScrollViewer 的高度希望这会有所帮助....