Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incremental Loading Behavior for ItemsView #600

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions components/Behaviors/OpenSolution.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@ECHO OFF

powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*
Binary file added components/Behaviors/samples/Assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions components/Behaviors/samples/Behaviors.Samples.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))" Condition="Exists('$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))')" />

<PropertyGroup>
<ToolkitComponentName>Behaviors</ToolkitComponentName>
</PropertyGroup>

<!-- Sets this up as a toolkit component's sample project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
<ItemGroup Condition="'$(IsWinAppSdk)' != 'true'">
<None Remove="NeedMoreItemTriggerBehaviorSample.xaml" />
<Page Remove="NeedMoreItemTriggerBehaviorSample.xaml" />
<Content Remove="NeedMoreItemTriggerBehaviorSample.xaml" />
<Resource Remove="NeedMoreItemTriggerBehaviorSample.xaml" />
<None Remove="LoadMoreItemBehaviorSample.xaml" />
<Page Remove="LoadMoreItemBehaviorSample.xaml" />
<Content Remove="LoadMoreItemBehaviorSample.xaml" />
<Resource Remove="LoadMoreItemBehaviorSample.xaml" />
<AdditionalFiles Remove="ItemsView Behaviors.md" />
<Content Remove="ItemsView Behaviors.md" />
<None Remove="ItemsView Behaviors.md" />
</ItemGroup>
</Project>
35 changes: 35 additions & 0 deletions components/Behaviors/samples/Dependencies.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.

MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.

For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<PackageReference Include="CommunityToolkit.Uwp.Behaviors" Version="8.0.230907"/>
<PackageReference Include="CommunityToolkit.Uwp.Animations" Version="8.0.230907"/>
</ItemGroup>

<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<PackageReference Include="CommunityToolkit.Uwp.Behaviors" Version="8.0.230907"/>
<PackageReference Include="CommunityToolkit.Uwp.Animations" Version="8.0.230907"/>
</ItemGroup>

<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.0.230907"/>
<PackageReference Include="CommunityToolkit.WinUI.Animations" Version="8.0.230907"/>
</ItemGroup>

<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.0.230907"/>
<PackageReference Include="CommunityToolkit.WinUI.Animations" Version="8.0.230907"/>
</ItemGroup>
</Project>
31 changes: 31 additions & 0 deletions components/Behaviors/samples/ItemsView Behaviors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: ItemsView Behaviors
author: githubaccount
description: A set of behaviors for the ItemsView control.
keywords: Behaviors, Control, Behavior
dev_langs:
- csharp
category: Xaml
subcategory: Behaviors
discussion-id: 532
issue-id: 0
icon: assets/icon.png
---
The new control `ItemsView` which can replace `ListView`&`GridView`, does not support `ISupportIncrementalLoading`.

Here are some Behaviors to help you make `ItemsView` support `ISupportIncrementalLoading`.

## NeedMoreItemTriggerBehaviorSample

This trigger behavior can excute actions when the `ItemsView` scrolling to bottom.
You can customize the loading behavior through actions, but note that you may need to debounce manually.

> [!SAMPLE NeedMoreItemTriggerBehaviorSample]

## LoadMoreItemBehaviorSample

If you don't have complex loading requirements, you can use this behavior.
It automatically calls `ISupportIncrementalLoading.LoadMoreItemsAsync` when the `ItemsSource` changes, in addition to when `ItemsView` scrolls to the bottom.
Besides, this behavior has a built-in debounce function.

> [!SAMPLE LoadMoreItemBehaviorSample]
49 changes: 49 additions & 0 deletions components/Behaviors/samples/LoadMoreItemBehaviorSample.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!-- 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="BehaviorsExperiment.Samples.LoadMoreItemBehaviorSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:BehaviorsExperiment.Samples"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mxuc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">

<Grid MaxHeight="300"
ColumnSpacing="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<ItemsView Grid.Column="0"
ItemsSource="{x:Bind ViewModels}">
<ItemsView.Layout>
<UniformGridLayout ItemsStretch="Fill"
MinColumnSpacing="5"
MinItemHeight="100"
MinItemWidth="100"
MinRowSpacing="5" />
</ItemsView.Layout>
<interactivity:Interaction.Behaviors>
<controls:LoadMoreItemBehavior IsActive="{x:Bind IsActive, Mode=OneWay}"
LoadCount="{x:Bind (x:Int32)LoadCount, Mode=OneWay}"
LoadingOffset="{x:Bind LoadingOffset, Mode=OneWay}" />
</interactivity:Interaction.Behaviors>
<ItemsView.ItemTemplate>
<DataTemplate x:DataType="x:Int32">
<ItemContainer>
<Rectangle Width="{x:Bind}"
Fill="{x:Bind local:LoadMoreItemBehaviorSample.GetColor()}" />
</ItemContainer>
</DataTemplate>
</ItemsView.ItemTemplate>
</ItemsView>
<TextBlock Grid.Column="1"
TextWrapping="Wrap">
<Run Text="Load more triggered " />
<Run Text="{x:Bind ViewModels.Num, Mode=OneWay}" />
<Run Text=" times" />
</TextBlock>
</Grid>
</Page>
84 changes: 84 additions & 0 deletions components/Behaviors/samples/LoadMoreItemBehaviorSample.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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.

#if WINAPPSDK

using CommunityToolkit.WinUI.Controls;
using Microsoft.UI;

namespace BehaviorsExperiment.Samples;

[ToolkitSampleBoolOption(nameof(LoadMoreItemBehavior.IsActive), true, Title = nameof(LoadMoreItemBehavior.IsActive))]
[ToolkitSampleNumericOption(nameof(LoadMoreItemBehavior.LoadingOffset), 100d, 50d, 500d, 50d, Title = nameof(LoadMoreItemBehavior.LoadingOffset))]
[ToolkitSampleNumericOption(nameof(LoadMoreItemBehavior.LoadCount), 20, 1, 50, 1, Title = nameof(LoadMoreItemBehavior.LoadCount))]

[ToolkitSample(id: nameof(LoadMoreItemBehaviorSample), "LoadMoreItemBehavior", description: $"A sample for showing how to create and use a LoadMoreItemBehavior.")]
public sealed partial class LoadMoreItemBehaviorSample : Page
{
private static readonly Random _random = new Random();

public LoadMoreItemBehaviorSample()
{
this.InitializeComponent();
}

public static SolidColorBrush GetColor()
{
var rand = _random.Next(4);
var color = rand switch
{
0 => Colors.Red,
1 => Colors.Blue,
2 => Colors.Green,
3 => Colors.Yellow,
_ => Colors.Black
};
return new(color);
}

public MyCollection ViewModels { get; } = [.. Enumerable.Repeat(0, 50).Select(_ => _random.Next(5, 10) * 500)];
}

public partial class MyCollection : ObservableCollection<int>, ISupportIncrementalLoading
{
private static readonly Random _random = new Random();

public int Num
{
get => _num;
set
{
if (_num == value)
{
return;
}

_num = value;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Num)));
}
}

private int _num;

public bool HasMoreItems => true;

public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
return LoadMoreItemsTaskAsync(count).AsAsyncOperation();
}

public async Task<LoadMoreItemsResult> LoadMoreItemsTaskAsync(uint count)
{
await Task.Delay(1000);
foreach (var i in Enumerable.Repeat(0, (int)count).Select(_ => _random.Next(5, 10) * 500))
{
Add(i);
}

Num++;
return new LoadMoreItemsResult { Count = count };
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!-- 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="BehaviorsExperiment.Samples.NeedMoreItemTriggerBehaviorSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:BehaviorsExperiment.Samples"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mxuc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">

<Grid MaxHeight="300" ColumnSpacing="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<ItemsView Grid.Column="0" ItemsSource="{x:Bind ViewModels}">
<ItemsView.Layout>
<UniformGridLayout
ItemsStretch="Fill"
MinColumnSpacing="5"
MinItemHeight="100"
MinItemWidth="100"
MinRowSpacing="5" />
</ItemsView.Layout>
<interactivity:Interaction.Behaviors>
<controls:NeedMoreItemTriggerBehavior IsActive="{x:Bind IsActive, Mode=OneWay}" LoadingOffset="{x:Bind LoadingOffset, Mode=OneWay}">
<core:CallMethodAction MethodName="IncrementCount" TargetObject="{x:Bind}" />
</controls:NeedMoreItemTriggerBehavior>

</interactivity:Interaction.Behaviors>
<ItemsView.ItemTemplate>
<DataTemplate x:DataType="x:Int32">
<ItemContainer>
<Rectangle Width="{x:Bind}" Fill="{x:Bind local:NeedMoreItemTriggerBehaviorSample.GetColor()}" />
</ItemContainer>
</DataTemplate>
</ItemsView.ItemTemplate>
</ItemsView>
<TextBlock Grid.Column="1" TextWrapping="Wrap">
<Run Text="CallMethodAction triggered " />
<Run x:Name="MyRun" Text="0" />
<Run Text=" times" />
</TextBlock>
</Grid>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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.

#if WINAPPSDK

using CommunityToolkit.WinUI.Controls;
using Microsoft.UI;

namespace BehaviorsExperiment.Samples;

[ToolkitSampleBoolOption(nameof(NeedMoreItemTriggerBehavior.IsActive), true, Title = nameof(NeedMoreItemTriggerBehavior.IsActive))]
[ToolkitSampleNumericOption(nameof(NeedMoreItemTriggerBehavior.LoadingOffset), 100d, 50d, 500d, 50d, Title = nameof(NeedMoreItemTriggerBehavior.LoadingOffset))]

[ToolkitSample(id: nameof(NeedMoreItemTriggerBehaviorSample), "NeedMoreItemTriggerBehavior", description: $"A sample for showing how to create and use a NeedMoreItemTriggerBehavior.")]
public sealed partial class NeedMoreItemTriggerBehaviorSample : Page
{
private static readonly Random _random = new();

public NeedMoreItemTriggerBehaviorSample()
{
this.InitializeComponent();
}

public static SolidColorBrush GetColor()
{
var rand = _random.Next(4);
var color = rand switch
{
0 => Colors.Red,
1 => Colors.Blue,
2 => Colors.Green,
3 => Colors.Yellow,
_ => Colors.Black
};
return new(color);
}

public IEnumerable<int> ViewModels { get; } = Enumerable.Repeat(0, 50).Select(_ => _random.Next(5, 10) * 500);

private int _num;

public void IncrementCount()
{
_num++;
MyRun.Text = _num.ToString();
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))" Condition="Exists('$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))')" />

<PropertyGroup>
<ToolkitComponentName>Behaviors</ToolkitComponentName>
<Description>This package contains Behaviors.</Description>
<!-- Rns suffix is required for namespaces shared across projects. See https://github.com/CommunityToolkit/Labs-Windows/issues/152 -->
<RootNamespace>CommunityToolkit.WinUI.Controls.BehaviorsRns</RootNamespace>
</PropertyGroup>

<!-- Sets this up as a toolkit component's source project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SourceProject.props" />
</Project>
35 changes: 35 additions & 0 deletions components/Behaviors/src/Dependencies.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.

MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.

For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<PackageReference Include="CommunityToolkit.Uwp.Behaviors" Version="8.0.230907"/>
<PackageReference Include="CommunityToolkit.Uwp.Animations" Version="8.0.230907"/>
</ItemGroup>

<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<PackageReference Include="CommunityToolkit.Uwp.Behaviors" Version="8.0.230907"/>
<PackageReference Include="CommunityToolkit.Uwp.Animations" Version="8.0.230907"/>
</ItemGroup>

<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.0.230907"/>
<PackageReference Include="CommunityToolkit.WinUI.Animations" Version="8.0.230907"/>
</ItemGroup>

<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.0.230907"/>
<PackageReference Include="CommunityToolkit.WinUI.Animations" Version="8.0.230907"/>
</ItemGroup>
</Project>
Loading