Turns out that writing a virtualizing panel (like VirtualizingStackPanel) is quite difficult. There are some good examples out on the web to give you a start (like here) but there turn out to be several further problems to overcome.
1) You have to deal with repositioning the scroll offset when the viewport and extent change relative size
That’s relatively straightforward – when you recalculate the viewport and the extent, you just need to scale by the relative changes: e.g.
_offset.X = (oldOffset.X / oldExtent.Width) * newExtent.Width;
2) You have to deal with focus handling, or ListBoxes (and other containers) won’t work properly
This is the most common problem with the existing examples.
By far the easiest way to do that is to realize one extra item off the beginning and the end of the visible area in each direction, and update your offsets accordingly. Don’t forget to check for the boundary conditions, where you’re already at the zeroth or (Count-1)th item in the collection.
3) Don’t forget that your panel can reach zero size, and may have infinite extent
Dealing with the infinities in the Measure() pass can be tricky. Don’t forget to check for them when it matters.
4) What about the case where you’re using it in a “non-virtualizing” manner
Sometimes, your VirtualizingPanel gets used in a non-Virtualizing context. You need logic to work out that there isn’t, in fact, an item container generator in play, and fall back on simple measuring of your InternalChildren. It should be possible to share your Arrange pass, though.
To help illustrate these points, I’ve hacked up an example virtualizing panel called EqualStackPanel. It behaves exactly like a stack panel, but fits the stack items to the available height/width of the container, depending on its Orientation. By default, it will try to fit all the items in the available space, but you can specify an alternative number of ItemsToDisplay, and it will fit exactly that many, and scroll to fit the remainder.
This isn’t production-hardened code, use at your own risk, your mileage may vary etc.
Ythos.EqualStackPanel.zip (17.49 KB)