您正遇到滚动的物理滚动和逻辑之间的差异。
正如你所发现的,每一个都有其折衷。
物理滚动
物理滚动(CanContentScroll = FALSE)只是像素得好,所以:
- 视口始终表示正是您的滚动程度的相同部分,给你一个平滑滚动经验和
但
- DataGrid的全部内容必须完全应用所有模板并进行测量和排列,以确定滚动条的大小,从而导致加载过程中的长时间延迟和高RAM使用率,并且它不会真的滚动项目所以它不理解ScrollIntoView很好
逻辑滚动
逻辑滚动(CanContentScroll =真)计算其滚动视口,并通过程度的项目,而不是像素,因此:
但
他们
之间进行选择,这些都是只有两种由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功能。我可以做这样的事情,但我会分配几个,也许很多天来让它正确。我建议你不要尝试。
非常感谢。 什么我可以做,使滚动条的大小在逻辑滚动更稳定?也许使用不同的滚动容器等。 – 2010-06-17 14:49:54
有三种选择可以改善这种情况:调整项目高度,重新模板ListBox/ScrollViewer/ScrollBar以使用自定义Track控件,或编写自己的虚拟化面板。我已经将所有这三个细节都添加到了答案中。 – 2010-06-17 15:42:35
废话..我试图把你的答案再一次,但是这只是删除了我的初始UP ..如果你编辑你的答案,我将能够重新申请:) – 2010-06-17 18:10:47