From 1169d499323d1f55e177662a16d261599a3abd68 Mon Sep 17 00:00:00 2001 From: Niels Laute Date: Tue, 11 Jul 2023 08:58:58 +0200 Subject: [PATCH 1/3] New Collections component --- components/Collections/OpenSolution.bat | 3 + .../samples/AdvancedCollectionView.md | 98 +++ .../samples/AdvancedCollectionViewSample.xaml | 67 ++ .../AdvancedCollectionViewSample.xaml.cs | 73 ++ .../samples/Assets/AdvancedCollectionView.png | Bin 0 -> 3573 bytes .../Collections/samples/Assets/AppIcon.png | Bin 0 -> 1348 bytes .../Assets/IncrementalLoadingCollection.png | Bin 0 -> 3062 bytes .../samples/Collections.Samples.csproj | 16 + .../Collections/samples/Dependencies.props | 31 + .../samples/IncrementalLoadingCollection.md | 71 ++ .../IncrementalLoadingCollectionSample.xaml | 69 ++ ...IncrementalLoadingCollectionSample.xaml.cs | 103 +++ .../Collections/src/AdditionalAssemblyInfo.cs | 13 + .../AdvancedCollectionView.Defer.cs | 55 ++ .../AdvancedCollectionView.Events.cs | 59 ++ .../AdvancedCollectionView.cs | 799 ++++++++++++++++++ .../IAdvancedCollectionView.cs | 81 ++ .../AdvancedCollectionView/SortDescription.cs | 70 ++ .../AdvancedCollectionView/SortDirection.cs | 21 + .../VectorChangedEventArgs.cs | 39 + .../CommunityToolkit.WinUI.Collections.csproj | 17 + components/Collections/src/Dependencies.props | 31 + .../IIncrementalSource.cs | 29 + .../IncrementalLoadingCollection.cs | 311 +++++++ components/Collections/src/MultiTarget.props | 9 + .../tests/Collections.Tests.projitems | 16 + .../tests/Collections.Tests.shproj | 13 + components/Collections/tests/DataSource.cs | 53 ++ .../tests/Test_AdvancedCollectionView.cs | 113 +++ .../Test_IncrementalLoadingCollection.cs | 143 ++++ 30 files changed, 2403 insertions(+) create mode 100644 components/Collections/OpenSolution.bat create mode 100644 components/Collections/samples/AdvancedCollectionView.md create mode 100644 components/Collections/samples/AdvancedCollectionViewSample.xaml create mode 100644 components/Collections/samples/AdvancedCollectionViewSample.xaml.cs create mode 100644 components/Collections/samples/Assets/AdvancedCollectionView.png create mode 100644 components/Collections/samples/Assets/AppIcon.png create mode 100644 components/Collections/samples/Assets/IncrementalLoadingCollection.png create mode 100644 components/Collections/samples/Collections.Samples.csproj create mode 100644 components/Collections/samples/Dependencies.props create mode 100644 components/Collections/samples/IncrementalLoadingCollection.md create mode 100644 components/Collections/samples/IncrementalLoadingCollectionSample.xaml create mode 100644 components/Collections/samples/IncrementalLoadingCollectionSample.xaml.cs create mode 100644 components/Collections/src/AdditionalAssemblyInfo.cs create mode 100644 components/Collections/src/AdvancedCollectionView/AdvancedCollectionView.Defer.cs create mode 100644 components/Collections/src/AdvancedCollectionView/AdvancedCollectionView.Events.cs create mode 100644 components/Collections/src/AdvancedCollectionView/AdvancedCollectionView.cs create mode 100644 components/Collections/src/AdvancedCollectionView/IAdvancedCollectionView.cs create mode 100644 components/Collections/src/AdvancedCollectionView/SortDescription.cs create mode 100644 components/Collections/src/AdvancedCollectionView/SortDirection.cs create mode 100644 components/Collections/src/AdvancedCollectionView/VectorChangedEventArgs.cs create mode 100644 components/Collections/src/CommunityToolkit.WinUI.Collections.csproj create mode 100644 components/Collections/src/Dependencies.props create mode 100644 components/Collections/src/IncrementalLoadingCollection/IIncrementalSource.cs create mode 100644 components/Collections/src/IncrementalLoadingCollection/IncrementalLoadingCollection.cs create mode 100644 components/Collections/src/MultiTarget.props create mode 100644 components/Collections/tests/Collections.Tests.projitems create mode 100644 components/Collections/tests/Collections.Tests.shproj create mode 100644 components/Collections/tests/DataSource.cs create mode 100644 components/Collections/tests/Test_AdvancedCollectionView.cs create mode 100644 components/Collections/tests/Test_IncrementalLoadingCollection.cs diff --git a/components/Collections/OpenSolution.bat b/components/Collections/OpenSolution.bat new file mode 100644 index 00000000..814a56d4 --- /dev/null +++ b/components/Collections/OpenSolution.bat @@ -0,0 +1,3 @@ +@ECHO OFF + +powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %* \ No newline at end of file diff --git a/components/Collections/samples/AdvancedCollectionView.md b/components/Collections/samples/AdvancedCollectionView.md new file mode 100644 index 00000000..dd83aae1 --- /dev/null +++ b/components/Collections/samples/AdvancedCollectionView.md @@ -0,0 +1,98 @@ +--- +title: AdvancedCollectionView +author: nmetulev +description: The AdvancedCollectionView is a collection view implementation that support filtering, sorting and incremental loading. It's meant to be used in a viewmodel. +keywords: AdvancedCollectionView, data, sorting, filtering +dev_langs: + - csharp +category: Helpers +subcategory: Data +discussion-id: 0 +issue-id: 0 +icon: Assets/AdvancedCollectionView.png +--- + +> [!Sample AdvancedCollectionViewSample] + +## Usage + +In your viewmodel instead of having a public [IEnumerable](/dotnet/core/api/system.collections.generic.ienumerable-1) of some sort to be bound to an eg. [Listview](/uwp/api/Windows.UI.Xaml.Controls.ListView), create a public AdvancedCollectionView and pass your list in the constructor to it. If you've done that you can use the many useful features it provides: + +* sorting your list using the `SortDirection` helper: specify any number of property names to sort on with the direction desired +* filtering your list using a [Predicate](/dotnet/core/api/system.predicate-1): this will automatically filter your list only to the items that pass the check by the predicate provided +* deferring notifications using the `NotificationDeferrer` helper: with a convenient _using_ pattern you can increase performance while doing large-scale modifications in your list by waiting with updates until you've completed your work +* incremental loading: if your source collection supports the feature then AdvancedCollectionView will do as well (it simply forwards the calls) +* live shaping: when constructing the `AdvancedCollectionView` you may specify that the collection use live shaping. This means that the collection will re-filter or re-sort if there are changes to the sort properties or filter properties that are specified using `ObserveFilterProperty` + +## Example + +```csharp +using Microsoft.Toolkit.Uwp.UI; + +// Grab a sample type +public class Person +{ + public string Name { get; set; } +} + +// Set up the original list with a few sample items +var oc = new ObservableCollection +{ + new Person { Name = "Staff" }, + new Person { Name = "42" }, + new Person { Name = "Swan" }, + new Person { Name = "Orchid" }, + new Person { Name = "15" }, + new Person { Name = "Flame" }, + new Person { Name = "16" }, + new Person { Name = "Arrow" }, + new Person { Name = "Tempest" }, + new Person { Name = "23" }, + new Person { Name = "Pearl" }, + new Person { Name = "Hydra" }, + new Person { Name = "Lamp Post" }, + new Person { Name = "4" }, + new Person { Name = "Looking Glass" }, + new Person { Name = "8" }, +}; + +// Set up the AdvancedCollectionView with live shaping enabled to filter and sort the original list +var acv = new AdvancedCollectionView(oc, true); + +// Let's filter out the integers +int nul; +acv.Filter = x => !int.TryParse(((Person)x).Name, out nul); + +// And sort ascending by the property "Name" +acv.SortDescriptions.Add(new SortDescription("Name", SortDirection.Ascending)); + +// Let's add a Person to the observable collection +var person = new Person { Name = "Aardvark" }; +oc.Add(person); + +// Our added person is now at the top of the list, but if we rename this person, we can trigger a re-sort +person.Name = "Zaphod"; // Now a re-sort is triggered and person will be last in the list + +// AdvancedCollectionView can be bound to anything that uses collections. +YourListView.ItemsSource = acv; +``` + +## Remarks + +_What source can I use?_ + +It's not necessary to use an eg. [ObservableCollection](/dotnet/core/api/system.collections.objectmodel.observablecollection-1) to use the AdvancedCollectionView. It works as expected even when providing a simple [List](/dotnet/core/api/system.collections.generic.list-1) in the constructor. + +_Any performance guidelines?_ + +If you're removing, modifying or inserting large amounts of items while having filtering and/or sorting set up, it's recommended that you use the `NotificationDeferrer` helper provided. It skips any performance heavy logic while it's in use, and automatically calls the `Refresh` method when disposed. + +```csharp +using (acv.DeferRefresh()) +{ + for (var i = 0; i < 500; i++) + { + acv.Add(new Person { Name = "defer" }); + } +} // acv.Refresh() gets called here +``` diff --git a/components/Collections/samples/AdvancedCollectionViewSample.xaml b/components/Collections/samples/AdvancedCollectionViewSample.xaml new file mode 100644 index 00000000..15060922 --- /dev/null +++ b/components/Collections/samples/AdvancedCollectionViewSample.xaml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + +