-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
30 changed files
with
2,403 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
@ECHO OFF | ||
|
||
powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Person> | ||
{ | ||
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 | ||
``` |
67 changes: 67 additions & 0 deletions
67
components/Collections/samples/AdvancedCollectionViewSample.xaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. --> | ||
<Page x:Class="AdvancedCollectionViewExperiment.Samples.AdvancedCollectionViewSample" | ||
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:AdvancedCollectionViewExperiment.Samples" | ||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
mc:Ignorable="d"> | ||
|
||
<Page.Resources> | ||
<Style x:Name="CardStyle" | ||
TargetType="Grid"> | ||
<Style.Setters> | ||
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" /> | ||
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" /> | ||
<Setter Property="BorderThickness" Value="1" /> | ||
<Setter Property="CornerRadius" Value="{StaticResource ControlCornerRadius}" /> | ||
</Style.Setters> | ||
</Style> | ||
<DataTemplate x:Key="PersonDataTemplate"> | ||
<TextBlock Text="{Binding Name}" /> | ||
</DataTemplate> | ||
</Page.Resources> | ||
<Grid ColumnSpacing="12" | ||
RowSpacing="8"> | ||
<Grid.ColumnDefinitions> | ||
<ColumnDefinition /> | ||
<ColumnDefinition /> | ||
</Grid.ColumnDefinitions> | ||
<Grid.RowDefinitions> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition /> | ||
</Grid.RowDefinitions> | ||
<StackPanel Grid.Column="0" | ||
Grid.ColumnSpan="2" | ||
Margin="0,24,0,24" | ||
Orientation="Horizontal" | ||
Spacing="8"> | ||
<TextBox x:Name="NewItemBox" | ||
MinWidth="320" | ||
PlaceholderText="Add new item" /> | ||
<Button x:Name="AddButton" | ||
VerticalAlignment="Bottom" | ||
Click="Add_Click" | ||
Content="Add" | ||
Style="{StaticResource AccentButtonStyle}" /> | ||
</StackPanel> | ||
<TextBlock Grid.Row="1" | ||
Text="Original list" /> | ||
<Grid Grid.Row="2" | ||
Style="{StaticResource CardStyle}"> | ||
<ListView x:Name="LeftList" | ||
ItemTemplate="{StaticResource PersonDataTemplate}" /> | ||
</Grid> | ||
<TextBlock Grid.Row="1" | ||
Grid.Column="1" | ||
Text="Sorted and filtered list (bound via AdvancedCollectionView)" /> | ||
<Grid Grid.Row="2" | ||
Grid.Column="1" | ||
Style="{StaticResource CardStyle}"> | ||
<ListView x:Name="RightList" | ||
ItemTemplate="{StaticResource PersonDataTemplate}" /> | ||
</Grid> | ||
</Grid> | ||
</Page> |
73 changes: 73 additions & 0 deletions
73
components/Collections/samples/AdvancedCollectionViewSample.xaml.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// 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 AdvancedCollectionViewExperiment.Samples; | ||
|
||
[ToolkitSample(id: nameof(AdvancedCollectionViewSample), "AdvancedCollectionView", description: $"A sample for showing how to create and use a {nameof(AdvancedCollectionView)}.")] | ||
public sealed partial class AdvancedCollectionViewSample : Page | ||
{ | ||
public ObservableCollection<Person>? oc; | ||
|
||
public AdvancedCollectionViewSample() | ||
{ | ||
this.InitializeComponent(); | ||
Setup(); | ||
} | ||
|
||
private void Setup() | ||
{ | ||
// left list | ||
oc = new ObservableCollection<Person> | ||
{ | ||
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" }, | ||
}; | ||
|
||
LeftList.ItemsSource = oc; | ||
|
||
// right list | ||
var acv = new AdvancedCollectionView(oc); | ||
int nul; | ||
acv.Filter = x => !int.TryParse(((Person)x).Name, out nul); | ||
acv.SortDescriptions.Add(new SortDescription("Name", SortDirection.Ascending)); | ||
|
||
RightList.ItemsSource = acv; | ||
} | ||
|
||
private void Add_Click(object sender, RoutedEventArgs e) | ||
{ | ||
if (!string.IsNullOrWhiteSpace(NewItemBox.Text)) | ||
{ | ||
oc!.Insert(0, new Person { Name = NewItemBox.Text }); | ||
NewItemBox.Text = ""; | ||
} | ||
} | ||
|
||
/// <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; } | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+2.99 KB
components/Collections/samples/Assets/IncrementalLoadingCollection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<Project Sdk="MSBuild.Sdk.Extras/3.0.23"> | ||
<PropertyGroup> | ||
<ToolkitComponentName>Collections</ToolkitComponentName> | ||
</PropertyGroup> | ||
|
||
<!-- 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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<!-- | ||
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="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> --> | ||
</ItemGroup> | ||
|
||
<!-- WinUI 2 / Uno --> | ||
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'"> | ||
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> --> | ||
</ItemGroup> | ||
|
||
<!-- WinUI 3 / WinAppSdk --> | ||
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'"> | ||
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> --> | ||
</ItemGroup> | ||
|
||
<!-- WinUI 3 / Uno --> | ||
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'"> | ||
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> --> | ||
</ItemGroup> | ||
</Project> |
71 changes: 71 additions & 0 deletions
71
components/Collections/samples/IncrementalLoadingCollection.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
--- | ||
title: IncrementalLoadingCollection | ||
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 (such as a ScrollViewer). | ||
keywords: IncrementalLoadingCollection, Control, Data, Incremental, Loading | ||
dev_langs: | ||
- csharp | ||
category: Helpers | ||
subcategory: Data | ||
discussion-id: 0 | ||
issue-id: 0 | ||
icon: Assets/IncrementalLoadingCollection.png | ||
--- | ||
|
||
> [!Sample IncrementalLoadingCollectionSample] | ||
[IIncrementalSource](/dotnet/api/microsoft.toolkit.collections.iincrementalsource-1) - An interface that represents a data source whose items can be loaded incrementally. | ||
|
||
[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. | ||
|
||
## 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; | ||
``` |
Oops, something went wrong.