Skip to content

Conversation

@MackinnonBuck
Copy link
Member

@MackinnonBuck MackinnonBuck commented Aug 14, 2020

Summary

With the changes in this PR, users will not have to specify an ItemSize when using <Virtualize>. It is still advantageous to do so, as it can avoid rendering the wrong number of items initially, but has no effect after the initial render.

Implementation Details

I've taken a different implementation approach than the one @SteveSandersonMS suggested in #24439 (comment), mostly because it's a nontrivial task to calculate the item height directly, at least from my investigation (one issue being that there could be more than one element in the template, so offsetHeight of the first element we find might not be enough). Following is an outline of how my implementation works:

  1. When parameters are set and the _itemSize member is not yet initialized, _itemSize is initialized to the ItemSize parameter (default is arbitrarily 50f if not specified by the user).

  2. After each render, _lastRenderedItemCount and _lastRenderedPlaceholderCount are updated to reflect how many items and placeholders were rendered, respectively.

  3. When a spacer becomes visible, a new piece of information is sent to the spacer callbacks - spacerSeparation - which is the space between the "before" and "after" spacers, calculated from spacerAfter.offsetTop - (spacerBefore.offsetTop + spacerBefore.offsetHeight).

  4. Assuming that placeholder size matches the current _itemSize1, we can use _lastRenderedItemCount and _lastRenderedPlaceholderCount to calculate how big each item would need to be to fill the remaining spacerSeparation (this is the new _itemSize).

Pros

Cons

  • 1This implementation depends on placeholders being _itemSize height. While it would be nice to find a way to not depend on this, I don't imagine it being a huge problem. The default placeholder always renders the correct size, and placeholders typically have more predictable content, so it should be relatively easy to render custom placeholders at the correct size. When not using an ItemsProvider, this isn't even a concern since placeholders don't have to be displayed. I could look into investigating a way for this to work even if users style their placeholder incorrectly, if we deem this to be too big a usability concern.
  • Rounding errors when calculating the item size can occur when items are very small (~5px). The effects of this are minor, and only result in the scrollbar moving slightly out of sync with the cursor, but it might be worth investigating a fix. Maybe if the calculated _itemSize is within some ε of the provided ItemSize, we stick with ItemSize?

Other Notes

I think the existing E2E tests validate these improvements. Justification:

  • RendersWhenItemSizeShrinks_Async validates that the item count increases when the item size shrinks (the bottom spacer becomes visible, causing a re-render with the new item size). Previously, the ItemSize parameter was used for all calculations, but since ItemSize is now used only on the first render, _itemSize must be properly updated for this test to pass.
  • Part of AlwaysFillsVisibleCapacity_Async validates that when new items are loaded, each placeholder is replaced with an item, but the total number of rendered list elements does not change. Since _itemSize is calculated in part by knowing how many placeholders and items are rendered, this test implicitly validates that _lastRenderedItemCount and _lastRenderedPlaceholderCount are calculated and utilized correctly to update _itemSize (if _itemSize changes after new items were rendered, a different number of elements will render and this test will fail).

TODO

  • Address some "cons" as necessary

Addresses #24439

@ghost ghost added the area-blazor Includes: Blazor, Razor Components label Aug 14, 2020
@MackinnonBuck MackinnonBuck marked this pull request as ready for review August 17, 2020 18:53
@MackinnonBuck MackinnonBuck requested review from a team and SteveSandersonMS as code owners August 17, 2020 18:53
@MackinnonBuck MackinnonBuck changed the base branch from master to release/5.0 August 18, 2020 23:19
@MackinnonBuck MackinnonBuck merged commit 6a3887a into release/5.0 Aug 19, 2020
@MackinnonBuck MackinnonBuck deleted the t-mabuc/remove-item-size-dependency branch August 19, 2020 03:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants