Skip to content

Commit 5a9fe7a

Browse files
committed
Restructured + infinite scroll
1 parent 96948a3 commit 5a9fe7a

17 files changed

+490
-168
lines changed

src/Components/Components/ref/Microsoft.AspNetCore.Components.netcoreapp.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,3 +587,60 @@ public void Dispose() { }
587587
public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; }
588588
}
589589
}
590+
namespace Microsoft.AspNetCore.Components.Virtualization
591+
{
592+
public sealed partial class InfiniteScroll<TItem> : Microsoft.AspNetCore.Components.Virtualization.VirtualizeBase<TItem>
593+
{
594+
public InfiniteScroll() { }
595+
[Microsoft.AspNetCore.Components.ParameterAttribute]
596+
public Microsoft.AspNetCore.Components.RenderFragment? InfiniteScrollFooter { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
597+
[Microsoft.AspNetCore.Components.ParameterAttribute]
598+
public Microsoft.AspNetCore.Components.RenderFragment<TItem> Item { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
599+
[Microsoft.AspNetCore.Components.ParameterAttribute]
600+
public int ItemBatchSize { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
601+
protected override int ItemCount { get { throw null; } }
602+
[Microsoft.AspNetCore.Components.ParameterAttribute]
603+
public System.Func<System.Range, System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<TItem>>> ItemsProvider { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
604+
protected override System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Components.RenderFragment> GetItems(int start, int count) { throw null; }
605+
}
606+
public partial interface IVirtualizationHelper : System.IAsyncDisposable
607+
{
608+
event System.EventHandler<Microsoft.AspNetCore.Components.Virtualization.SpacerEventArgs> BottomSpacerVisible;
609+
event System.EventHandler<Microsoft.AspNetCore.Components.Virtualization.SpacerEventArgs> TopSpacerVisible;
610+
System.Threading.Tasks.ValueTask InitAsync(Microsoft.AspNetCore.Components.ElementReference topSpacer, Microsoft.AspNetCore.Components.ElementReference bottomSpacer);
611+
}
612+
public partial interface IVirtualizationService
613+
{
614+
Microsoft.AspNetCore.Components.Virtualization.IVirtualizationHelper CreateVirtualizationHelper();
615+
}
616+
public partial class SpacerEventArgs : System.EventArgs
617+
{
618+
public SpacerEventArgs(float spacerSize, float containerSize) { }
619+
public float ContainerSize { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
620+
public float SpacerSize { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
621+
}
622+
public abstract partial class VirtualizeBase<TItem> : Microsoft.AspNetCore.Components.ComponentBase, System.IAsyncDisposable
623+
{
624+
protected VirtualizeBase() { }
625+
protected abstract int ItemCount { get; }
626+
[Microsoft.AspNetCore.Components.ParameterAttribute]
627+
public float ItemSize { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
628+
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { }
629+
[System.Diagnostics.DebuggerStepThroughAttribute]
630+
public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }
631+
protected abstract System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Components.RenderFragment> GetItems(int start, int count);
632+
[System.Diagnostics.DebuggerStepThroughAttribute]
633+
protected override System.Threading.Tasks.Task OnAfterRenderAsync(bool firstRender) { throw null; }
634+
protected override void OnParametersSet() { }
635+
}
636+
public sealed partial class Virtualize<TItem> : Microsoft.AspNetCore.Components.Virtualization.VirtualizeBase<TItem>
637+
{
638+
public Virtualize() { }
639+
[Microsoft.AspNetCore.Components.ParameterAttribute]
640+
public Microsoft.AspNetCore.Components.RenderFragment<TItem>? ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
641+
protected override int ItemCount { get { throw null; } }
642+
[Microsoft.AspNetCore.Components.ParameterAttribute]
643+
public System.Collections.Generic.ICollection<TItem> Items { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
644+
protected override System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Components.RenderFragment> GetItems(int start, int count) { throw null; }
645+
}
646+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Threading.Tasks;
6+
7+
namespace Microsoft.AspNetCore.Components.Virtualization
8+
{
9+
/// <summary>
10+
/// Describes a helper for detecting and relaying virtualization events.
11+
/// </summary>
12+
public interface IVirtualizationHelper : IAsyncDisposable
13+
{
14+
/// <summary>
15+
/// Performs platform-specific initialization.
16+
/// </summary>
17+
/// <param name="topSpacer">The <see cref="ElementReference"/> representing the top spacer.</param>
18+
/// <param name="bottomSpacer">The <see cref="ElementReference"/> representing the bottom spacer.</param>
19+
/// <returns>The <see cref="ValueTask"/> associated with the completion of this operation.</returns>
20+
ValueTask InitAsync(ElementReference topSpacer, ElementReference bottomSpacer);
21+
22+
/// <summary>
23+
/// Invoked when the top spacer becomes visible.
24+
/// </summary>
25+
event EventHandler<SpacerEventArgs> TopSpacerVisible;
26+
27+
/// <summary>
28+
/// Invoked when the bottom spacer becomes visible.
29+
/// </summary>
30+
event EventHandler<SpacerEventArgs> BottomSpacerVisible;
31+
}
32+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.AspNetCore.Components.Virtualization
5+
{
6+
/// <summary>
7+
/// Describes services enabling platform-specific virtualization.
8+
/// </summary>
9+
public interface IVirtualizationService
10+
{
11+
/// <summary>
12+
/// Creates a helper used for detecting and relaying virtualization events.
13+
/// </summary>
14+
/// <returns></returns>
15+
IVirtualizationHelper CreateVirtualizationHelper();
16+
}
17+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Concurrent;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
11+
namespace Microsoft.AspNetCore.Components.Virtualization
12+
{
13+
/// <summary>
14+
/// Provides functionality for rendering a virtualized, infinite list of items.
15+
/// </summary>
16+
/// <typeparam name="TItem">The <c>context</c> type for the items being rendered.</typeparam>
17+
public sealed class InfiniteScroll<TItem> : VirtualizeBase<TItem>
18+
{
19+
private readonly ConcurrentQueue<TItem> _loadedItems = new ConcurrentQueue<TItem>();
20+
21+
private int _fetchingItems;
22+
23+
protected override int ItemCount => InfiniteScrollFooter == null ? _loadedItems.Count : _loadedItems.Count + 1;
24+
25+
/// <summary>
26+
/// Gets or sets the list item template.
27+
/// </summary>
28+
[Parameter]
29+
public RenderFragment<TItem> Item { get; set; } = default!;
30+
31+
/// <summary>
32+
/// Gets or sets the infinite scroll footer template.
33+
/// </summary>
34+
[Parameter]
35+
public RenderFragment? InfiniteScrollFooter { get; set; }
36+
37+
/// <summary>
38+
/// Gets or sets the function that provides items for the inifinite scroll.
39+
/// </summary>
40+
[Parameter]
41+
public Func<Range, Task<IEnumerable<TItem>>> ItemsProvider { get; set; } = default!;
42+
43+
/// <summary>
44+
/// The batch size in which items are fetched.
45+
/// </summary>
46+
[Parameter]
47+
public int ItemBatchSize { get; set; }
48+
49+
protected override IEnumerable<RenderFragment> GetItems(int start, int count)
50+
{
51+
if (start + count >= _loadedItems.Count)
52+
{
53+
// Fetch more items if we're not already
54+
FetchItemsAsync();
55+
56+
var items = _loadedItems.Skip(start).Select(item => Item(item));
57+
58+
return InfiniteScrollFooter == null ? items : items.Append(InfiniteScrollFooter);
59+
}
60+
else
61+
{
62+
return _loadedItems.Skip(start).Take(count).Select(item => Item(item));
63+
}
64+
}
65+
66+
private void FetchItemsAsync()
67+
{
68+
if (Interlocked.Exchange(ref _fetchingItems, 1) == 0)
69+
{
70+
ItemsProvider(new Range(_loadedItems.Count, _loadedItems.Count + ItemBatchSize)).ContinueWith(t =>
71+
{
72+
foreach (var item in t.Result)
73+
{
74+
_loadedItems.Enqueue(item);
75+
}
76+
77+
_fetchingItems = 0;
78+
79+
InvokeAsync(() => StateHasChanged());
80+
});
81+
}
82+
}
83+
}
84+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace Microsoft.AspNetCore.Components.Virtualization
7+
{
8+
/// <summary>
9+
/// Describes an event involving a spacer in a virtualized list.
10+
/// </summary>
11+
public class SpacerEventArgs : EventArgs
12+
{
13+
/// <summary>
14+
/// The new size of the spacer.
15+
/// </summary>
16+
public float SpacerSize { get; }
17+
18+
/// <summary>
19+
/// The current size of the spacer's container.
20+
/// </summary>
21+
public float ContainerSize { get; }
22+
23+
/// <summary>
24+
/// Instantiates a new <see cref="SpacerEventArgs"/> instance.
25+
/// </summary>
26+
/// <param name="spacerSize">The new size of the spacer.</param>
27+
/// <param name="containerSize">The current size of the spacer's container.</param>
28+
public SpacerEventArgs(float spacerSize, float containerSize)
29+
{
30+
SpacerSize = spacerSize;
31+
ContainerSize = containerSize;
32+
}
33+
}
34+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
namespace Microsoft.AspNetCore.Components.Virtualization
8+
{
9+
/// <summary>
10+
/// Provides functionality for rendering a virtualized, fixed-size list of items.
11+
/// </summary>
12+
/// <typeparam name="TItem">The <c>context</c> type for the items being rendered.</typeparam>
13+
public sealed class Virtualize<TItem> : VirtualizeBase<TItem>
14+
{
15+
protected override int ItemCount => Items.Count;
16+
17+
/// <summary>
18+
/// Gets or sets the content template for list items.
19+
/// </summary>
20+
[Parameter]
21+
public RenderFragment<TItem>? ChildContent { get; set; }
22+
23+
/// <summary>
24+
/// Gets or sets the collection of items used to generate the list.
25+
/// </summary>
26+
[Parameter]
27+
public ICollection<TItem> Items { get; set; } = default!;
28+
29+
protected override IEnumerable<RenderFragment> GetItems(int start, int count)
30+
{
31+
return ChildContent == null ?
32+
Enumerable.Empty<RenderFragment>() :
33+
Items.Skip(start).Take(count).Select(item => ChildContent.Invoke(item));
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)