ScrollViewer的视口高度VS实际高度 [英] ScrollViewer's Viewport Height VS Actual Height

查看:459
本文介绍了ScrollViewer的视口高度VS实际高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这两个都是相当笼统的术语,但我很好奇,除了我们使用虚拟化的情况外,这些高度何时会有所不同?

Both are quite general terms but I'm curious to know when these height will be different apart from the case we're using Virtualization?

另一个问题: 我在MSDN上阅读:

One more question: I read on MSDN:

如果CanContentScroll为true,则ExtentHeight,ScrollableHeight,ViewportHeight和VerticalOffset属性的值是项目数.如果CanContentScroll为false,则这些属性的值为设备无关像素".

但是我遇到ViewPort Height问题:我在应用程序中有2个列表框:
1.已启用虚拟化且CanContentScroll = True.
2.没有虚拟化且CanContentScroll = True.

However I'm facing an issue with ViewPort Height: I've 2 listbox in application:
1. Which have Virtualization Enabled and CanContentScroll = True.
2. Which have no virtualization and CanContentScroll = True.

在列表框1中,同时将视口高度"拖放到4/5(当前可见的元素数).但是在ListBox 2中,我得到的视口高度等于Listbox的实际高度.

In ListBox 1 while drag-drop Viewport Height comes to 4/5 (Number of elements currently visible). However in ListBox 2 i get Viewport Height equal to Actual Height of Listbox.

为什么会有这种区别?

更多发现:
1.可滚动高度是在scrollviewer中不可见的项目数
2.视口高度是scrollviewer中可见的项目数.
因此,视口高度+ ScrollableHeight =范围高度

Few more findings:
1. Scrollable Height is number of items not visible in scrollviewer
2. Viewport Height is number of items visible in scrollviewer.
Thus Viewport Height + ScrollableHeight = Extent Height

有人可以解释两个列表框之间的区别吗?如果使用列表框1,我需要使用ViewPort

推荐答案

最后,这是根本原因:

您遇到的是物理滚动和逻辑滚动之间的差异.

You are encountering the differences between physical scrolling and logical scrolling.

正如您所发现的,每个都有其权衡.

As you have discovered, each has its tradeoffs.

物理滚动

物理滚动(CanContentScroll = false)仅按像素移动,因此:

Physical scrolling (CanContentScroll=false) just goes by pixels, so:

视口始终代表滚动范围的完全相同的部分,从而为您提供流畅的滚动体验,并且 但是

The viewport always represents exactly the same portion of your scroll extent, giving you a smooth scrolling experience, and but

DataGrid的全部内容必须完全应用所有模板,并进行测量和安排以确定滚动条的大小,从而导致加载期间的长时间延迟和较高的RAM使用率,以及 它不会真正滚动项目,因此无法很好地理解ScrollIntoView 逻辑滚动

The entire contents of the DataGrid must have all templates fully applied and be measured and arranged to determine the size of the scrollbar, leading to long delays during loading and high RAM usage, and It doesn't really scroll items so it doesn't understand ScrollIntoView very well Logical scrolling

逻辑滚动(CanContentScroll = true)按项目而不是像素计算其滚动视口和范围,因此:

Logical scrolling (CanContentScroll=true) calculates its scroll viewport and extent by items instead of pixels, so:

视口在不同时间可能显示不同数量的项目,这意味着视口中的项目数量与范围内的项目数量相比有所不同,从而导致滚动条长度发生变化,并且

The viewport may show a different number of items at different times, meaning the number of items in the viewport as compared to the number of items in the extent varies, causing the scrollbar length to change, and

滚动从一项移动到另一项,并且从不移动到另一项,从而导致生涩的"滚动

Scrolling moves from one item to the next and never in between, leading to "jerky" scrolling

但是

只要您在后台使用VirtualizingStackPanel,它只需要应用模板并测量和排列当前实际可见的项目,并且

As long as you're using VirtualizingStackPanel under the hood, it only needs to apply templates and measure and arrange the items that are actually visible at the moment, and

ScrollIntoView简单得多,因为它只需要在视图中获取正确的项目索引即可

ScrollIntoView is much simpler since it just needs to get the right item index into view

在它们之间进行选择

这是WPF提供的仅有的两种滚动.您必须根据上述折衷在它们之间进行选择.通常,逻辑滚动最适合中型到大型数据集,而物理滚动最适合小型数据集.

These are the only two kinds of scrolling provided by WPF. You must choose between them based on the above tradeoffs. Generally logical scrolling is best for medium to large datasets, and physical scrolling is best for small ones.

在物理滚动过程中加快加载速度的一个技巧是使物理滚动更好,方法是将商品包装在具有固定大小的自定义装饰器中,并在不可见时将其子项的可见性"设置为隐藏".这样可以防止在您准备好发生该事件的子代控件上时应用ApplyTemplate,Measure和Arrange.

A trick to speed loading during physical scrolling is to make the physical scrolling better is to wrap your items in a custom Decorator that has a fixed size and sets its child's Visibility to Hidden when it is not visible. This prevents the ApplyTemplate, Measure and Arrange from occuring on the descendant controls of that item until you're ready for it to happen.

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

A trick to make physical scrolling's ScrollIntoView more reliable is to call it twice: Once immediately and once in a dispatcher callback of DispatcherPriority.ApplicationIdle.

使逻辑滚动滚动条更稳定

Making logical scroll scrollbar more stable

如果所有项目的高度均相同,则视口中可见的项目数将随时保持不变,从而导致滚动条尺寸保持不变(因为如果项目不变,则与总数量的比率) ).

If all your items are the same height, the number of items visible in the viewport at any time will stay the same, causing the scroll thumb size to stay the same (because the ratio with total number if items doesn't change).

还可以修改ScrollBar本身的行为,以便始终将拇指计算为固定大小.要做到这一点而无需任何恶意代码:

It is also possible to modify the behavior of the ScrollBar itself so the thumb is always calculated to be a fixed size. To do this without any hacky code-behind:

  • 子类跟踪以替换 拇指位置和 自己在MeasureOverride中设置大小
  • 更改使用的ScrollBar模板
    用于逻辑滚动ScrollBar
    改用您的子类别的Track 普通的

  • Subclass Track to replace the calculation of Thumb position and size in MeasureOverride with your own
  • Change the ScrollBar template used
    for the logical-scrolling ScrollBar
    to use your subclassed Track instead of the regular one

更改ScrollViewer模板 明确设置您的自定义 ScrollBar模板上的 逻辑滚动ScrollBar
(而不是使用默认
模板)

Change the ScrollViewer template to explicitly set your custom ScrollBar template on the logical-scrolling ScrollBar
(instead of using the default
template)

这意味着从内置的WPF模板复制很多模板代码,因此这不是一个很好的解决方案.但这的替代方法是使用隐藏代码,等待所有模板扩展,然后找到ScrollBar并将ScrollBar模板替换为使用自定义Track的模板.该代码保存了两个大模板(ListBox,ScrollViewer),但付出了一些非常棘手的代码.

This means copying a lot of template code fom the built-in WPF templates, so it is not a very elegant solution. But the alternative to this is to use hacky code-behind to wait until all the templates are expanded, then find the ScrollBar and just replace the ScrollBar template with the one that uses your custom Track. This code saves two large templates (ListBox, ScrollViewer) at the cost of some very tricky code.

使用其他面板将需要大量工作:VirtualizingStackPanel是唯一虚拟化的面板,并且只有它和StackPanel才能进行逻辑滚动.由于您要利用VirtualizingStackPanel的虚拟化功能,因此必须重新实现所有这些功能以及所有IScrollInfo信息功能以及常规的Panel功能.我可以做类似的事情,但是我会花几天甚至很多天来做对.我建议您不要尝试.

Using a different Panel would be a much larger amount of work: VirtualizingStackPanel is the only Panel that virtualizes, and only it and StackPanel to logical scrolling. Since you are taking advantage of VirtualizingStackPanel's virtualization abilities you would have to re-implement all of these plus all IScrollInfo info function plus your regular Panel functions. I could do something like that but I would allocate several, perhaps many, days to get it right. I recommend you not try it.

礼貌-物理滚动与逻辑滚动

这篇关于ScrollViewer的视口高度VS实际高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆