@@ -31,6 +31,12 @@ public sealed class Virtualize<TItem> : ComponentBase, IVirtualizeJsCallbacks, I
31
31
32
32
private int _loadedItemsStartIndex ;
33
33
34
+ private int _lastRenderedItemCount ;
35
+
36
+ private int _lastRenderedPlaceholderCount ;
37
+
38
+ private float _itemSize ;
39
+
34
40
private IEnumerable < TItem > ? _loadedItems ;
35
41
36
42
private CancellationTokenSource ? _refreshCts ;
@@ -65,10 +71,10 @@ public sealed class Virtualize<TItem> : ComponentBase, IVirtualizeJsCallbacks, I
65
71
public RenderFragment < PlaceholderContext > ? Placeholder { get ; set ; }
66
72
67
73
/// <summary>
68
- /// Gets the size of each item in pixels.
74
+ /// Gets the size of each item in pixels. Defaults to 50px.
69
75
/// </summary>
70
76
[ Parameter ]
71
- public float ItemSize { get ; set ; }
77
+ public float ItemSize { get ; set ; } = 50f ;
72
78
73
79
/// <summary>
74
80
/// Gets or sets the function providing items to the list.
@@ -88,7 +94,12 @@ protected override void OnParametersSet()
88
94
if ( ItemSize <= 0 )
89
95
{
90
96
throw new InvalidOperationException (
91
- $ "{ GetType ( ) } requires a positive value for parameter '{ nameof ( ItemSize ) } ' to perform virtualization.") ;
97
+ $ "{ GetType ( ) } requires a positive value for parameter '{ nameof ( ItemSize ) } '.") ;
98
+ }
99
+
100
+ if ( _itemSize <= 0 )
101
+ {
102
+ _itemSize = ItemSize ;
92
103
}
93
104
94
105
if ( ItemsProvider != null )
@@ -154,11 +165,13 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
154
165
{
155
166
// This is a rare case where it's valid for the sequence number to be programmatically incremented.
156
167
// This is only true because we know for certain that no other content will be alongside it.
157
- builder . AddContent ( renderIndex , _placeholder , new PlaceholderContext ( renderIndex ) ) ;
168
+ builder . AddContent ( renderIndex , _placeholder , new PlaceholderContext ( renderIndex , _itemSize ) ) ;
158
169
}
159
170
160
171
builder . CloseRegion ( ) ;
161
172
173
+ _lastRenderedItemCount = 0 ;
174
+
162
175
// Render the loaded items.
163
176
if ( _loadedItems != null && _itemTemplate != null )
164
177
{
@@ -171,18 +184,22 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
171
184
foreach ( var item in itemsToShow )
172
185
{
173
186
_itemTemplate ( item ) ( builder ) ;
174
- renderIndex ++ ;
187
+ _lastRenderedItemCount ++ ;
175
188
}
176
189
190
+ renderIndex += _lastRenderedItemCount ;
191
+
177
192
builder . CloseRegion ( ) ;
178
193
}
179
194
195
+ _lastRenderedPlaceholderCount = Math . Max ( 0 , lastItemIndex - _itemsBefore - _lastRenderedItemCount ) ;
196
+
180
197
builder . OpenRegion ( 5 ) ;
181
198
182
199
// Render the placeholders after the loaded items.
183
200
for ( ; renderIndex < lastItemIndex ; renderIndex ++ )
184
201
{
185
- builder . AddContent ( renderIndex , _placeholder , new PlaceholderContext ( renderIndex ) ) ;
202
+ builder . AddContent ( renderIndex , _placeholder , new PlaceholderContext ( renderIndex , _itemSize ) ) ;
186
203
}
187
204
188
205
builder . CloseRegion ( ) ;
@@ -197,28 +214,45 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
197
214
}
198
215
199
216
private string GetSpacerStyle ( int itemsInSpacer )
200
- => $ "height: { itemsInSpacer * ItemSize } px;";
217
+ => $ "height: { itemsInSpacer * _itemSize } px;";
201
218
202
- void IVirtualizeJsCallbacks . OnBeforeSpacerVisible ( float spacerSize , float containerSize )
219
+ void IVirtualizeJsCallbacks . OnBeforeSpacerVisible ( float spacerSize , float spacerSeparation , float containerSize )
203
220
{
204
- CalcualteItemDistribution ( spacerSize , containerSize , out var itemsBefore , out var visibleItemCapacity ) ;
221
+ CalcualteItemDistribution ( spacerSize , spacerSeparation , containerSize , out var itemsBefore , out var visibleItemCapacity ) ;
205
222
206
223
UpdateItemDistribution ( itemsBefore , visibleItemCapacity ) ;
207
224
}
208
225
209
- void IVirtualizeJsCallbacks . OnAfterSpacerVisible ( float spacerSize , float containerSize )
226
+ void IVirtualizeJsCallbacks . OnAfterSpacerVisible ( float spacerSize , float spacerSeparation , float containerSize )
210
227
{
211
- CalcualteItemDistribution ( spacerSize , containerSize , out var itemsAfter , out var visibleItemCapacity ) ;
228
+ CalcualteItemDistribution ( spacerSize , spacerSeparation , containerSize , out var itemsAfter , out var visibleItemCapacity ) ;
212
229
213
230
var itemsBefore = Math . Max ( 0 , _itemCount - itemsAfter - visibleItemCapacity ) ;
214
231
215
232
UpdateItemDistribution ( itemsBefore , visibleItemCapacity ) ;
216
233
}
217
234
218
- private void CalcualteItemDistribution ( float spacerSize , float containerSize , out int itemsInSpacer , out int visibleItemCapacity )
235
+ private void CalcualteItemDistribution (
236
+ float spacerSize ,
237
+ float spacerSeparation ,
238
+ float containerSize ,
239
+ out int itemsInSpacer ,
240
+ out int visibleItemCapacity )
219
241
{
220
- itemsInSpacer = Math . Max ( 0 , ( int ) Math . Floor ( spacerSize / ItemSize ) - 1 ) ;
221
- visibleItemCapacity = ( int ) Math . Ceiling ( containerSize / ItemSize ) + 2 ;
242
+ if ( _lastRenderedItemCount > 0 )
243
+ {
244
+ _itemSize = ( spacerSeparation - ( _lastRenderedPlaceholderCount * _itemSize ) ) / _lastRenderedItemCount ;
245
+ }
246
+
247
+ if ( _itemSize <= 0 )
248
+ {
249
+ // At this point, something unusual has occurred, likely due to misuse of this component.
250
+ // Reset the calculated item size to the user-provided item size.
251
+ _itemSize = ItemSize ;
252
+ }
253
+
254
+ itemsInSpacer = Math . Max ( 0 , ( int ) Math . Floor ( spacerSize / _itemSize ) - 1 ) ;
255
+ visibleItemCapacity = ( int ) Math . Ceiling ( containerSize / _itemSize ) + 2 ;
222
256
}
223
257
224
258
private void UpdateItemDistribution ( int itemsBefore , int visibleItemCapacity )
@@ -285,7 +319,7 @@ private ValueTask<ItemsProviderResult<TItem>> DefaultItemsProvider(ItemsProvider
285
319
private RenderFragment DefaultPlaceholder ( PlaceholderContext context ) => ( builder ) =>
286
320
{
287
321
builder . OpenElement ( 0 , "div" ) ;
288
- builder . AddAttribute ( 1 , "style" , $ "height: { ItemSize } px;") ;
322
+ builder . AddAttribute ( 1 , "style" , $ "height: { _itemSize } px;") ;
289
323
builder . CloseElement ( ) ;
290
324
} ;
291
325
0 commit comments