Skip to content

Commit

Permalink
Adding samples
Browse files Browse the repository at this point in the history
  • Loading branch information
niels9001 authored and Arlodotexe committed Jun 6, 2023
1 parent d88d444 commit 744e6ab
Show file tree
Hide file tree
Showing 13 changed files with 765 additions and 267 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@

<!-- Sets this up as a toolkit component's sample project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
<ItemGroup>
<None Remove="Assets\AppIcon.png" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\AppIcon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
title: IncrementalLoadingCollection
author: githubaccount
description: TODO: Your experiment's description here
keywords: IncrementalLoadingCollection, Control, Layout
author: nmetulev
description: The IncrementalLoadingCollection helpers greatly simplify the definition and usage of collections whose items can be loaded incrementally only when needed by the view
keywords: IncrementalLoadingCollection, Control, Data, Incremental, Loading
dev_langs:
- csharp
category: Controls
Expand All @@ -11,22 +11,85 @@ discussion-id: 0
issue-id: 0
---

<!-- To know about all the available Markdown syntax, Check out https://docs.microsoft.com/contribute/markdown-reference -->
<!-- Ensure you remove all comments before submission, to ensure that there are no formatting issues when displaying this page. -->
<!-- It is recommended to check how the Documentation will look in the sample app, before Merging a PR -->
<!-- **Note:** All links to other docs.microsoft.com pages should be relative without locale, i.e. for the one above would be /contribute/markdown-reference -->
<!-- Included images should be optimized for size and not include any Intellectual Property references. -->
# Incremental Loading Collection Helpers

<!-- Be sure to update the discussion/issue numbers above with your Labs discussion/issue id numbers in order for UI links to them from the sample app to work. -->
The **IncrementalLoadingCollection** helpers greatly simplify the definition and usage of collections whose items can be loaded incrementally only when needed by the view, i.e., when user scrolls a [ListView](/uwp/api/Windows.UI.Xaml.Controls.ListView) or a [GridView](/uwp/api/Windows.UI.Xaml.Controls.GridView).

# IncrementalLoadingCollection
> [!Sample IncrementalLoadingCollectionSample]
TODO: Fill in information about this experiment and how to get started here...
[IIncrementalSource](/dotnet/api/microsoft.toolkit.collections.iincrementalsource-1) - An interface that represents a data source whose items can be loaded incrementally.

## Custom Control
[IncrementalLoadingCollection](/dotnet/api/microsoft.toolkit.uwp.incrementalloadingcollection-2) - An extension of [ObservableCollection](/dotnet/api/system.collections.objectmodel.observablecollection-1) such that its items are loaded only when needed.

You can inherit from an existing component as well, like `Panel`, this example shows a control without a
XAML Style that will be more light-weight to consume by an app developer:
## IncrementalLoadingCollection Properties

> [!Sample IncrementalLoadingCollectionCustomSample]
| Property | Type | Description |
| -- | -- | -- |
| CurrentPageIndex | int | Gets or sets a value indicating The zero-based index of the current items page |
| HasMoreItems | bool | Gets a value indicating whether the collection contains more items to retrieve |
| IsLoading | bool | Gets a value indicating whether new items are being loaded |
| ItemsPerPage | int | Gets a value indicating how many items that must be retrieved for each incremental call |
| OnEndLoading | [Action](/dotnet/api/system.action) | Gets or sets an Action that is called when a retrieval operation ends |
| OnError | Action\<Exception> | Gets or sets an Action that is called if an error occours during data retrieval. The actual Exception is passed as an argument |
| OnStartLoading | Action | Gets or sets an Action that is called when a retrieval operation begins |

## IncrementalLoadingCollection Methods

| Methods | Return Type | Description |
| -- | -- | -- |
| LoadDataAsync(CancellationToken) | Task<IEnumerable\<IType>> | Actually performs the incremental loading |
| LoadMoreItemsAsync(UInt32) | IAsyncOperation\<LoadMoreItemsResult> | Initializes incremental loading from the view |
| Refresh() | void | Clears the collection and resets the page index which triggers an automatic reload of the first page |
| RefreshAsync() | Task | Clears the collection and reloads data from the source |

## Example

`IIncrementalSource` allows to define the data source:

```csharp
// Be sure to include the using at the top of the file:
//using CommunityToolkit.WinUI;
public class Person
{
public string Name { get; set; }
}

public class PeopleSource : IIncrementalSource<Person>
{
private readonly List<Person> people;

public PeopleSource()
{
// Creates an example collection.
people = new List<Person>();

for (int i = 1; i <= 200; i++)
{
var p = new Person { Name = "Person " + i };
people.Add(p);
}
}

public async Task<IEnumerable<Person>> GetPagedItemsAsync(int pageIndex, int pageSize)
{
// Gets items from the collection according to pageIndex and pageSize parameters.
var result = (from p in people
select p).Skip(pageIndex * pageSize).Take(pageSize);

// Simulates a longer request...
await Task.Delay(1000);

return result;
}
}
```

The *GetPagedItemsAsync* method is invoked every time the view need to show more items.

`IncrementalLoadingCollection` can then be bound to a [ListView](/uwp/api/Windows.UI.Xaml.Controls.ListView) or a [GridView-like](/uwp/api/Windows.UI.Xaml.Controls.GridView) control:

```csharp
var collection = new IncrementalLoadingCollection<PeopleSource, Person>();
PeopleListView.ItemsSource = collection;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="IncrementalLoadingCollectionExperiment.Samples.IncrementalLoadingCollectionSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:IncrementalLoadingCollectionExperiment.Samples"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid MaxWidth="460"
HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<StackPanel HorizontalAlignment="Left">
<TextBlock Text="Items are loaded incrementally when the view needs to show them (i.e., when the user scrolls the ListView)"
TextWrapping="Wrap" />
<Button Margin="0,12,0,12"
Click="RefreshCollection"
Content="Refresh collection"
Style="{StaticResource AccentButtonStyle}" />
<TextBlock>
<Run Text="Is loading:" />
<Run FontWeight="SemiBold"
Text="{Binding IsLoading, Mode=OneWay}" />
</TextBlock>
<TextBlock>
<Run Text="Has more items:" />
<Run FontWeight="SemiBold"
Text="{Binding HasMoreItems, Mode=OneWay}" />
</TextBlock>

</StackPanel>

<Grid Grid.Row="2"
MaxHeight="420"
Margin="0,24,0,0"
VerticalAlignment="Top"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="4">
<ListView x:Name="PeopleListView">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Width="24"
Height="24"
VerticalAlignment="Center"
Source="ms-appx:///Assets/AppIcon.png" />
<TextBlock Grid.Column="1"
Margin="12"
VerticalAlignment="Center"
Text="{Binding Name}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using CommunityToolkit.WinUI;

namespace IncrementalLoadingCollectionExperiment.Samples;

[ToolkitSample(id: nameof(IncrementalLoadingCollectionSample), "Incremental Loading Collection", description: $"A sample for showing how to create and use a IncrementalLoadingCollection.")]
public sealed partial class IncrementalLoadingCollectionSample : Page
{
public IncrementalLoadingCollectionSample()
{
this.InitializeComponent();
Load();
}
private void Load()
{
// IncrementalLoadingCollection can be bound to a GridView or a ListView. In this case it is a ListView called PeopleListView.
var collection = new IncrementalLoadingCollection<PeopleSource, Person>();
PeopleListView.ItemsSource = collection;

// Binds the collection to the page DataContext in order to use its IsLoading and HasMoreItems properties.
DataContext = collection;
}

private async void RefreshCollection(object sender, RoutedEventArgs e)
{
var collection = (IncrementalLoadingCollection<PeopleSource, Person>)PeopleListView.ItemsSource;
await collection.RefreshAsync();
}
}
67 changes: 67 additions & 0 deletions components/IncrementalLoadingCollection/samples/PeopleSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using CommunityToolkit.WinUI;

namespace IncrementalLoadingCollectionExperiment.Samples;

/// <summary>
/// A sample implementation of the <see cref="Collections.IIncrementalSource{TSource}"/> interface.
/// </summary>
/// <seealso cref="Collections.IIncrementalSource{TSource}"/>
public class PeopleSource : IIncrementalSource<Person>
{
private readonly List<Person> _people;

/// <summary>
/// Initializes a new instance of the <see cref="PeopleSource"/> class.
/// </summary>
public PeopleSource()
{
// Creates an example collection.
_people = new List<Person>();

for (int i = 1; i <= 200; i++)
{
var p = new Person { Name = "Person " + i };
_people.Add(p);
}
}

/// <summary>
/// Retrieves items based on <paramref name="pageIndex"/> and <paramref name="pageSize"/> arguments.
/// </summary>
/// <param name="pageIndex">
/// The zero-based index of the page that corresponds to the items to retrieve.
/// </param>
/// <param name="pageSize">
/// The number of <see cref="Person"/> items to retrieve for the specified <paramref name="pageIndex"/>.
/// </param>
/// <param name="cancellationToken">
/// Used to propagate notification that operation should be canceled.
/// </param>
/// <returns>
/// Returns a collection of <see cref="Person"/>.
/// </returns>
public async Task<IEnumerable<Person>> GetPagedItemsAsync(int pageIndex, int pageSize, CancellationToken cancellationToken = default(CancellationToken))
{
// Gets items from the collection according to pageIndex and pageSize parameters.
var result = (from p in _people
select p).Skip(pageIndex * pageSize).Take(pageSize);

// Simulates a longer request...
// Make sure the list is still in order after a refresh,
// even if the first page takes longer to load
if (pageIndex == 0)
{
await Task.Delay(2000);
}
else
{
await Task.Delay(1000);
}

return result;
}
}
16 changes: 16 additions & 0 deletions components/IncrementalLoadingCollection/samples/Person.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace IncrementalLoadingCollectionExperiment.Samples;

/// <summary>
/// A sample class used to show how to use the <see cref="Collections.IIncrementalSource{TSource}"/> interface.
/// </summary>
public class Person
{
/// <summary>
/// Gets or sets the name of the person.
/// </summary>
public string? Name { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>IncrementalLoadingCollection</ToolkitComponentName>
<Description>This package contains IncrementalLoadingCollection.</Description>
<Version>0.0.1</Version>

<!-- Rns suffix is required for namespaces shared across projects. See https://github.com/CommunityToolkit/Labs-Windows/issues/152 -->
<RootNamespace>CommunityToolkit.WinUI.IncrementalLoadingCollectionRns</RootNamespace>
</PropertyGroup>

<!-- Sets this up as a toolkit component's source project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SourceProject.props" />
</Project>
29 changes: 29 additions & 0 deletions components/IncrementalLoadingCollection/src/IIncrementalSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace CommunityToolkit.WinUI;

/// <summary>
/// This interface represents a data source whose items can be loaded incrementally.
/// </summary>
/// <typeparam name="TSource">Type of collection element.</typeparam>
public interface IIncrementalSource<TSource>
{
/// <summary>
/// This method is invoked every time the view need to show more items. Retrieves items based on <paramref name="pageIndex"/> and <paramref name="pageSize"/> arguments.
/// </summary>
/// <param name="pageIndex">
/// The zero-based index of the page that corresponds to the items to retrieve.
/// </param>
/// <param name="pageSize">
/// The number of <typeparamref name="TSource"/> items to retrieve for the specified <paramref name="pageIndex"/>.
/// </param>
/// <param name="cancellationToken">
/// Used to propagate notification that operation should be canceled.
/// </param>
/// <returns>
/// Returns a collection of <typeparamref name="TSource"/>.
/// </returns>
Task<IEnumerable<TSource>> GetPagedItemsAsync(int pageIndex, int pageSize, CancellationToken cancellationToken = default);
}
Loading

0 comments on commit 744e6ab

Please sign in to comment.