2010-06-17 81 views
12

我有一个解决方案,其中i根据用户标准产生一个数据网格(或多个实例)..每个网格保持接收数据,因为它通过的ObservableCollectionWPF数据网格:CanContentScroll属性引起奇怪的行为

问题我有进来,这是滚动的怪异。它不稳定,滚动条会在滚动时自行调整大小。

比我发现.. CanContentScroll property!它完全修复了奇怪的滚动行为,给我带来了临时的幸福和快乐。

但是,它会导致2个不幸的副作用。

  1. 每当我重新创建网格实例并将其绑定到我观察到的集合,它冻结了我的整个窗口,持续5秒。当我的网格增长到一个很大的尺寸时,这个延迟可能持续30秒。

  2. 当我调用TradeGrid.ScrollIntoView(TradeGrid.Items(TradeGrid.Items.Count - 1))滚动到底部时,它跳到底部并且返回顶部。

是否有另一种方法来实现平滑滚动也许?

回答

36

您正遇到滚动的物理滚动和逻辑之间的差异。

正如你所发现的,每一个都有其折衷。

物理滚动

物理滚动(CanContentScroll = FALSE)只是像素得好,所以:

  • 视口始终表示正是您的滚动程度的相同部分,给你一个平滑滚动经验和

  • DataGrid的全部内容必须完全应用所有模板并进行测量和排列,以确定滚动条的大小,从而导致加载过程中的长时间延迟和高RAM使用率,并且它不会真的滚动项目所以它不理解ScrollIntoView很好

逻辑滚动

逻辑滚动(CanContentScroll =真)计算其滚动视口,并通过程度的项目,而不是像素,因此:

  • 视口可能显示不同的数目在不同的时间项,与项中的程度的数目意在视口中的项目的数目而变化,从而引起滚动条长度发生变化,并

  • 滚动从一个项目移至之间的下一个,决不,导致“干”滚动

  • 只要你在底层使用VirtualizingStackPanel,它只需要应用模板并测量和排列目前实际可见的项目,而且ScrollIntoView更简单,因为它只需要获取权项指标进入视野

他们

之间进行选择,这些都是只有两种由WPF提供滚动的。您必须根据上述折衷选择它们。一般来说,逻辑滚动对于大中型数据集来说是最好的,而物理滚动对于小型数据集来说是最好的。

在物理滚动过程中加速加载的一个技巧是让物理滚动更好是将您的项目包装在具有固定大小的自定义装饰器中,并在其不可见时将其子项的可见性设置为隐藏。这可以防止ApplyTemplate,Measure和Arrange发生在该项目的后代控件上,直到您准备好实现它。

使物理滚动的ScrollIntoView更可靠的一个窍门是调用它两次:一次立即,一次在DispatcherPriority.ApplicationIdle的调度程序回调中。

决策逻辑滚动滚动条更稳定

如果所有的项目都具有相同的高度,在任何时间视口中可见将保持不变的项目数,造成滚动拇指大小保持不变(因为如果项目没有改变,则与总数的比率)。

也可以修改ScrollBar本身的行为,以便拇指始终计算为固定大小。要做到这一点,没有任何哈克后台代码:

  • 子类跟踪与自己
  • 更改用于逻辑滚动滚动条来使用你的子类的滚动条的模板,以取代在的MeasureOverride拇指位置和大小的计算跟踪常规one
  • 变化,而不是的ScrollViewer模板明确设置您的自定义滚动条的模板上的逻辑滚动滚动条(而不是使用默认的模板)
  • 更改列表框模板使用显式上设置自定义的ScrollViewer模板它创建的ScrollViewer

这意味着复制大量的模板代码从内置的WPF模板,所以它不是一个非常优雅的解决方案。但是替代方案是使用hacky代码隐藏来等待所有模板展开,然后找到ScrollBar,并将ScrollBar模板替换为使用自定义Track的ScrollBar模板。此代码以一些非常棘手的代码为代价保存两个大型模板(ListBox,ScrollViewer)。

使用不同的面板将是一个更大的工作量:VirtualizingStackPanel是唯一的虚拟化面板,只有它和StackPanel才能进行逻辑滚动。由于您正在利用VirtualizingStackPanel的虚拟化功能,因此您必须重新实现所有这些功能以及所有IScrollInfo信息功能以及常规Panel功能。我可以做这样的事情,但我会分配几个,也许很多天来让它正确。我建议你不要尝试。

+0

非常感谢。 什么我可以做,使滚动条的大小在逻辑滚动更稳定?也许使用不同的滚动容器等。 – 2010-06-17 14:49:54

+1

有三种选择可以改善这种情况:调整项目高度,重新模板ListBox/ScrollViewer/ScrollBar以使用自定义Track控件,或编写自己的虚拟化面板。我已经将所有这三个细节都添加到了答案中。 – 2010-06-17 15:42:35

+0

废话..我试图把你的答案再一次,但是这只是删除了我的初始UP ..如果你编辑你的答案,我将能够重新申请:) – 2010-06-17 18:10:47

2

我也有同样的问题,我的DataGrid和最后我做到:

ScrollViewer.CanContentScroll="True" 
EnableRowVirtualization="True" 
VirtualizingPanel.VirtualizationMode="Standard" 

现在一切都在我的DataGrid工作的罚款。

+0

没有设置VirtualizingPanel.VirtualizationMode,我发现性能更好。将其设置为“回收”会导致滚动(强制滚动条在物理上滚动)并设置为“标准”以某种方式导致滚动较慢,这很奇怪,因为我认为默认值为“标准”,但给它一个明确的设置滞后滚动。不明白为什么。 – KMC 2017-06-06 12:16:07