Use ItemsRepeater in ListBox etc
See original GitHub issueOur current item virtualization code has a few problems:
- It doesn’t handle differently sized items very well (#2144)
- It assumes that 1 item = one scroll unit, meaning that it can’t handle layouts that display multiple items per line (i.e. a wrapping panel, a grid)
- It doesn’t handle smooth scrolling
- It doesn’t correctly handle
ListBoxItem
children (#2936)
One of the main problems with supporting these scenarios is that the materialization of items due to changes in the source collection happens in the CollectionChanged
event handler. Beacuse this occurs outside the layout pass, changes made here then trigger a layout pass. When that layout pass occurs, the virtualization algorithm is re-run, possibly with different constraints. This can cause the item that was scrolled to to be scrolled back out of the viewport, causing #2144. This could be worked around by storing temporary state to pass to the coming layout pass, however in some cases that layout pass will not occur meaning that the temporary state will be passed to a subsequent unrelated layout pass, causing other problems.
Another problem with creating the items in the CollectionChanged
handler, is that we can potentially be doing much more materialization/dematerialization than required.
Initial attempt to fix this
My initial attempt to fix this involved moving the materialization of items to the layout pass, however the fact that we use a Panel
to display the containers made this difficult: you don’t know which containers need to be visible until the measure pass has completed, so I started by removing all Children
from the container at the start of the measure pass and adding them back in. This unfortunately broke things because as controls are removed from Children
they are also removed from the visual/logical tree, causing the focused element to lose focus among other things.
The solution to this would be to modify virtualizing panels to have a “virtual” list of children for the measure pass, which is then synchronized with the real Children
on arrange, or to somehow delay visual/logical tree detachment. To me these solutions seem like a hack to get around the real problem: that Panel
s aren’t the right solution for virtualization.
And this is just to fix point 1) above.
ItemsRepeater
UWP seem to have come to the same conclusion and have introduced Attached Layouts. This is a really powerful virtualization framework that would handle all points above, plus more, including nesting and grouping. In addition this is all MIT-licenced code with its source on GitHub.
UWP doesn’t use ItemsRepeater
for its list boxes, assumedly for back-compat reasons, but we don’t have that problem being pre-1.0, and I think it could be used to implement a new ItemsPresenter
or similar in Avalonia.
Unfortunately the code is written in C++/CX and there’s a quite a lot of it, so porting may not be easy.
ItemsRepeater
has now been ported to Avalonia; the next step is to rewrite ItemsPresenter
to use it.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:15
- Comments:8 (7 by maintainers)
Top GitHub Comments
Update on this: I’ve given up hoping that the upstream WinUI
ItemsRepeater
will ever be fixed enough to use it as a core component of ourItemsControl
s, in particular these issues are blockers:https://github.com/microsoft/microsoft-ui-xaml/issues/1829 https://github.com/microsoft/microsoft-ui-xaml/issues/1422
I have a proof of concept for a virtualized stack panel which may fix many of our current problems with
ListBox
, and also allow smooth scrolling without breaking API compatibility, I hope to get more time to work on it in a few months.Closing this issue for now.
Now that
ItemsRepeater
is ported from UWP, I plan to reworkItemsPresenter
to be anItemsRepeater
in the 0.10 timeline. Currently #3040 is blocking that though.