From 200408342b208941d5d7b3ff80287d16d0df0324 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 11:14:33 -0400 Subject: [PATCH 01/13] QuickGrid: -Adds Multi column sorting capability -Exposes SortColumns so that individual columns can easily apply their own logic based on whether or not they're currently being sorted by. Use cases like swapping an icon out in markup, changing available options, etc. --- .../src/Columns/GridSort.cs | 32 +++++++++++--- .../src/Columns/SortColumn.cs | 18 ++++++++ .../src/GridItemsProviderRequest.cs | 44 ++++++++++--------- .../src/QuickGrid.razor.cs | 33 +++++++++++--- 4 files changed, 95 insertions(+), 32 deletions(-) create mode 100644 src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/SortColumn.cs diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/GridSort.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/GridSort.cs index 0e891b2e206f..51a65171736f 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/GridSort.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/GridSort.cs @@ -15,6 +15,7 @@ public sealed class GridSort private const string ExpressionNotRepresentableMessage = "The supplied expression can't be represented as a property name for sorting. Only simple member expressions, such as @(x => x.SomeProperty), can be converted to property names."; private readonly Func, bool, IOrderedQueryable> _first; + private readonly Func, bool, IOrderedQueryable> _thenFirst; private List, bool, IOrderedQueryable>>? _then; private (LambdaExpression, bool) _firstExpression; @@ -23,10 +24,14 @@ public sealed class GridSort private IReadOnlyCollection? _cachedPropertyListAscending; private IReadOnlyCollection? _cachedPropertyListDescending; - internal GridSort(Func, bool, IOrderedQueryable> first, (LambdaExpression, bool) firstExpression) + internal GridSort( + Func, bool, IOrderedQueryable> first, + (LambdaExpression, bool) firstExpression, + Func, bool, IOrderedQueryable> thenFirst) { _first = first; _firstExpression = firstExpression; + _thenFirst = thenFirst; _then = default; _thenExpressions = default; } @@ -39,7 +44,8 @@ internal GridSort(Func, bool, IOrderedQueryable /// A instance representing the specified sorting rule. public static GridSort ByAscending(Expression> expression) => new((queryable, asc) => asc ? queryable.OrderBy(expression) : queryable.OrderByDescending(expression), - (expression, true)); + (expression, true), + (queryable, asc) => asc ? queryable.ThenBy(expression) : queryable.ThenByDescending(expression)); /// /// Produces a instance that sorts according to the specified , descending. @@ -49,7 +55,8 @@ public static GridSort ByAscending(Expression> /// A instance representing the specified sorting rule. public static GridSort ByDescending(Expression> expression) => new((queryable, asc) => asc ? queryable.OrderByDescending(expression) : queryable.OrderBy(expression), - (expression, false)); + (expression, false), + (queryable, asc) => asc ? queryable.ThenByDescending(expression) : queryable.ThenBy(expression)); /// /// Updates a instance by appending a further sorting rule. @@ -85,9 +92,9 @@ public GridSort ThenDescending(Expression> expr return this; } - internal IOrderedQueryable Apply(IQueryable queryable, bool ascending) + internal IOrderedQueryable Apply(IQueryable queryable, bool ascending, bool firstColumn) { - var orderedQueryable = _first(queryable, ascending); + var orderedQueryable = ApplyCore(queryable, ascending, firstColumn); if (_then is not null) { @@ -100,6 +107,21 @@ internal IOrderedQueryable Apply(IQueryable queryable, boo return orderedQueryable; } + private IOrderedQueryable ApplyCore(IQueryable queryable, bool ascending, bool firstColumn) + { + if (firstColumn) + { + return _first(queryable, ascending); + } + + if (queryable is not IOrderedQueryable src) + { + throw new InvalidOperationException($"Expected {typeof(IOrderedQueryable)} since this is not the first sort column."); + } + + return _thenFirst(src, ascending); + } + internal IReadOnlyCollection ToPropertyList(bool ascending) { if (ascending) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/SortColumn.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/SortColumn.cs new file mode 100644 index 000000000000..8ec9d3151f1d --- /dev/null +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/SortColumn.cs @@ -0,0 +1,18 @@ +namespace Microsoft.AspNetCore.Components.QuickGrid; + +/// +/// Provides information about the column that has sorting applied. +/// +/// The type of data represented by each row in the grid. +public class SortColumn +{ + /// + /// The column that has sorting applied. + /// + public ColumnBase? Column { get; init; } + + /// + /// Whether or not the sort is ascending. + /// + public bool Ascending { get; internal set; } +} diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs index 5c634a28ce0b..7810eedb9cef 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs @@ -22,20 +22,13 @@ public readonly struct GridItemsProviderRequest public int? Count { get; init; } /// - /// Specifies which column represents the sort order. - /// + /// Specifies which columns are currently being sorted. + /// /// Rather than inferring the sort rules manually, you should normally call either - /// or , since they also account for and automatically. + /// or , since they also account for + /// and automatically. /// - public ColumnBase? SortByColumn { get; init; } - - /// - /// Specifies the current sort direction. - /// - /// Rather than inferring the sort rules manually, you should normally call either - /// or , since they also account for and automatically. - /// - public bool SortByAscending { get; init; } + public IReadOnlyList> SortColumns { get; init; } /// /// A token that indicates if the request should be cancelled. @@ -43,13 +36,11 @@ public readonly struct GridItemsProviderRequest public CancellationToken CancellationToken { get; init; } internal GridItemsProviderRequest( - int startIndex, int? count, ColumnBase? sortByColumn, bool sortByAscending, - CancellationToken cancellationToken) + int startIndex, int? count, IReadOnlyList> sortColumns, CancellationToken cancellationToken) { StartIndex = startIndex; Count = count; - SortByColumn = sortByColumn; - SortByAscending = sortByAscending; + SortColumns = sortColumns; CancellationToken = cancellationToken; } @@ -58,13 +49,26 @@ internal GridItemsProviderRequest( /// /// An . /// A new representing the with sorting rules applied. - public IQueryable ApplySorting(IQueryable source) => - SortByColumn?.SortBy?.Apply(source, SortByAscending) ?? source; + public IQueryable ApplySorting(IQueryable source) + { + for (var i = 0; i < SortColumns.Count; i++) + { + var sortColumn = SortColumns[i]; + source = sortColumn.Column.SortBy.Apply(source, sortColumn.Ascending, i == 0); + } + + return source; + } /// /// Produces a collection of (property name, direction) pairs representing the sorting rules. /// /// A collection of (property name, direction) pairs representing the sorting rules - public IReadOnlyCollection GetSortByProperties() => - SortByColumn?.SortBy?.ToPropertyList(SortByAscending) ?? Array.Empty(); + public IEnumerable> GetSortByProperties() + { + foreach (var sortColumn in SortColumns) + { + yield return sortColumn.Column.SortBy?.ToPropertyList(sortColumn.Ascending) ?? []; + } + } } diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs index 363ad846cbf7..464d92a3b312 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs @@ -242,6 +242,13 @@ private void FinishCollectingColumns() _collectingColumns = false; } + private List> _sortByColumns = []; + + /// + /// The list of columns that have sorting applied. + /// + public IReadOnlyList> SortColumns => _sortByColumns; + /// /// Sets the grid's current sort column to the specified . /// @@ -250,16 +257,28 @@ private void FinishCollectingColumns() /// A representing the completion of the operation. public Task SortByColumnAsync(ColumnBase column, SortDirection direction = SortDirection.Auto) { - _sortByAscending = direction switch + _sortByColumns.RemoveAll(sbc => sbc.Column != column); + return AddUpdateSortByColumnAsync(column, direction); + } + + public Task AddUpdateSortByColumnAsync(ColumnBase column, SortDirection direction = SortDirection.Auto) + { + var sortBy = _sortByColumns.FirstOrDefault(sbc => sbc.Column == column); + + if (sortBy == null) + { + sortBy = new() { Column = column }; + _sortByColumns.Add(sortBy); + } + + sortBy.Ascending = direction switch { SortDirection.Ascending => true, SortDirection.Descending => false, - SortDirection.Auto => _sortByColumn != column || !_sortByAscending, - _ => throw new NotSupportedException($"Unknown sort direction {direction}"), + SortDirection.Auto => !sortBy.Ascending, + _ => throw new NotSupportedException($"Unknown sort direction {direction}") }; - _sortByColumn = column; - StateHasChanged(); // We want to see the updated sort order in the header, even before the data query is completed return RefreshDataAsync(); } @@ -320,7 +339,7 @@ private async Task RefreshDataCoreAsync() _lastRefreshedPaginationStateHash = Pagination?.GetHashCode(); var startIndex = Pagination is null ? 0 : (Pagination.CurrentPageIndex * Pagination.ItemsPerPage); var request = new GridItemsProviderRequest( - startIndex, Pagination?.ItemsPerPage, _sortByColumn, _sortByAscending, thisLoadCts.Token); + startIndex, Pagination?.ItemsPerPage, SortColumns, thisLoadCts.Token); var result = await ResolveItemsRequestAsync(request); if (!thisLoadCts.IsCancellationRequested) { @@ -356,7 +375,7 @@ private async Task RefreshDataCoreAsync() } var providerRequest = new GridItemsProviderRequest( - startIndex, count, _sortByColumn, _sortByAscending, request.CancellationToken); + startIndex, count, SortColumns, request.CancellationToken); var providerResult = await ResolveItemsRequestAsync(providerRequest); if (!request.CancellationToken.IsCancellationRequested) From bed1adfed4e87c6563734249e754b19a6854fc2b Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 13:30:32 -0400 Subject: [PATCH 02/13] Adds license header to SortColumn --- .../src/Columns/SortColumn.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/SortColumn.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/SortColumn.cs index 8ec9d3151f1d..361ae0efc9c8 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/SortColumn.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Columns/SortColumn.cs @@ -1,4 +1,7 @@ -namespace Microsoft.AspNetCore.Components.QuickGrid; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Components.QuickGrid; /// /// Provides information about the column that has sorting applied. From cf275759570b881b5ffd0fe24332aceefa836279 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 13:31:45 -0400 Subject: [PATCH 03/13] Adds null check before calling sortColumn.Column.SortBy.Apply Adds null check to sortColumn.Column in GetSortByProperties --- .../src/GridItemsProviderRequest.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs index 7810eedb9cef..4500d918e8ca 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs @@ -54,7 +54,11 @@ public IQueryable ApplySorting(IQueryable source) for (var i = 0; i < SortColumns.Count; i++) { var sortColumn = SortColumns[i]; - source = sortColumn.Column.SortBy.Apply(source, sortColumn.Ascending, i == 0); + + if (sortColumn.Column?.SortBy != null) + { + source = sortColumn.Column.SortBy.Apply(source, sortColumn.Ascending, i == 0); + } } return source; @@ -68,7 +72,7 @@ public IEnumerable> GetSortByProperties() { foreach (var sortColumn in SortColumns) { - yield return sortColumn.Column.SortBy?.ToPropertyList(sortColumn.Ascending) ?? []; + yield return sortColumn.Column?.SortBy?.ToPropertyList(sortColumn.Ascending) ?? []; } } } From 8fd09c944a6703450652b994757ac2324ca52e95 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 13:32:13 -0400 Subject: [PATCH 04/13] Updates relevant parts of PublicAPI.Shipped.txt --- .../src/PublicAPI.Shipped.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt index 1b580b50deff..3910855f96ca 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt @@ -41,12 +41,10 @@ Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Ca Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.CancellationToken.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Count.get -> int? Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Count.init -> void -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GetSortByProperties() -> System.Collections.Generic.IReadOnlyCollection! +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GetSortByProperties() -> System.Collections.Generic.IEnumerable!>! Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GridItemsProviderRequest() -> void -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByAscending.get -> bool -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByAscending.init -> void -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByColumn.get -> Microsoft.AspNetCore.Components.QuickGrid.ColumnBase? -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByColumn.init -> void +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortColumns.get -> System.Collections.Generic.IReadOnlyList!>! +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortColumns.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.StartIndex.get -> int Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.StartIndex.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderResult From 4c5d833f2362761460cb2035bdbaa6724d92eb24 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 13:47:29 -0400 Subject: [PATCH 05/13] Adds SortColumn to PublicAPI.Shipped.txt --- .../src/PublicAPI.Shipped.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt index 3910855f96ca..a144e44e05e6 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt @@ -120,6 +120,11 @@ Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Theme.get -> stri Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Theme.set -> void Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Virtualize.get -> bool Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Virtualize.set -> void +Microsoft.AspNetCore.Components.QuickGrid.SortColumn +Microsoft.AspNetCore.Components.QuickGrid.SortColumn.Ascending.get -> bool +Microsoft.AspNetCore.Components.QuickGrid.SortColumn.Column.get -> Microsoft.AspNetCore.Components.QuickGrid.ColumnBase? +Microsoft.AspNetCore.Components.QuickGrid.SortColumn.Column.init -> void +Microsoft.AspNetCore.Components.QuickGrid.SortColumn.SortColumn() -> void Microsoft.AspNetCore.Components.QuickGrid.SortDirection Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Ascending = 1 -> Microsoft.AspNetCore.Components.QuickGrid.SortDirection Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Auto = 0 -> Microsoft.AspNetCore.Components.QuickGrid.SortDirection From a72550d8c41709810d5e2c9af58c5240db80fa18 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 13:49:37 -0400 Subject: [PATCH 06/13] Adds QuickGrid.SortColumns.get to PublicAPI.Shipped.txt --- .../src/PublicAPI.Shipped.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt index a144e44e05e6..c4603d5faa92 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt @@ -116,6 +116,7 @@ Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.QuickGrid() -> vo Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.RefreshDataAsync() -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.ShowColumnOptionsAsync(Microsoft.AspNetCore.Components.QuickGrid.ColumnBase! column) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.SortByColumnAsync(Microsoft.AspNetCore.Components.QuickGrid.ColumnBase! column, Microsoft.AspNetCore.Components.QuickGrid.SortDirection direction = Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Auto) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.SortColumns.get -> System.Collections.Generic.IReadOnlyList!>! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Theme.get -> string? Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Theme.set -> void Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Virtualize.get -> bool From ed82cedbe2ba3c3110cd259448d04caa8e8b747e Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 13:51:17 -0400 Subject: [PATCH 07/13] Marks _sortByColumns readonly --- .../src/QuickGrid.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs index 464d92a3b312..b5c3c644d0b4 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs @@ -242,7 +242,7 @@ private void FinishCollectingColumns() _collectingColumns = false; } - private List> _sortByColumns = []; + private readonly List> _sortByColumns = []; /// /// The list of columns that have sorting applied. From 39c8e552acd63be5bc96e0da8abf3d683be59339 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 13:51:42 -0400 Subject: [PATCH 08/13] Adds QuickGrid.AddUpdateSortByColumnAsync to PublicAPI.Shipped.txt --- .../src/PublicAPI.Shipped.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt index c4603d5faa92..1bbfa61deb54 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt @@ -95,6 +95,7 @@ Microsoft.AspNetCore.Components.QuickGrid.PropertyColumn.Prope Microsoft.AspNetCore.Components.QuickGrid.QuickGrid Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.AdditionalAttributes.get -> System.Collections.Generic.IReadOnlyDictionary? Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.AdditionalAttributes.set -> void +Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.AddUpdateSortByColumnAsync(Microsoft.AspNetCore.Components.QuickGrid.ColumnBase! column, Microsoft.AspNetCore.Components.QuickGrid.SortDirection direction = Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Auto) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.ChildContent.get -> Microsoft.AspNetCore.Components.RenderFragment? Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.ChildContent.set -> void Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Class.get -> string? From 4e649aba4a4a0a948a2ef827b462969ffa61e913 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 13:54:50 -0400 Subject: [PATCH 09/13] Adds documentation to AddUpdateSortByColumnAsync --- .../src/QuickGrid.razor.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs index b5c3c644d0b4..7c9511420075 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs @@ -261,6 +261,14 @@ public Task SortByColumnAsync(ColumnBase column, SortDirection direct return AddUpdateSortByColumnAsync(column, direction); } + /// + /// Adds or updates sorting of the specified . + /// If the column is not already being tracked it will be appended, otherwise it's direction is updated with it's position unchanged. + /// + /// The column that defines the new sort order. + /// The direction of sorting. If the value is , then it will toggle the direction on each call. + /// A representing the completion of the operation. + /// public Task AddUpdateSortByColumnAsync(ColumnBase column, SortDirection direction = SortDirection.Auto) { var sortBy = _sortByColumns.FirstOrDefault(sbc => sbc.Column == column); From 7a5d28bf3f1e54a2802c0343c1b3e4c0af452e5f Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 14:13:59 -0400 Subject: [PATCH 10/13] Moves to Unshipped --- .../src/PublicAPI.Shipped.txt | 15 +++++---------- .../src/PublicAPI.Unshipped.txt | 12 +++++++++++- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt index 1bbfa61deb54..1b580b50deff 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt @@ -41,10 +41,12 @@ Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Ca Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.CancellationToken.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Count.get -> int? Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Count.init -> void -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GetSortByProperties() -> System.Collections.Generic.IEnumerable!>! +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GetSortByProperties() -> System.Collections.Generic.IReadOnlyCollection! Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GridItemsProviderRequest() -> void -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortColumns.get -> System.Collections.Generic.IReadOnlyList!>! -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortColumns.init -> void +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByAscending.get -> bool +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByAscending.init -> void +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByColumn.get -> Microsoft.AspNetCore.Components.QuickGrid.ColumnBase? +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByColumn.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.StartIndex.get -> int Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.StartIndex.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderResult @@ -95,7 +97,6 @@ Microsoft.AspNetCore.Components.QuickGrid.PropertyColumn.Prope Microsoft.AspNetCore.Components.QuickGrid.QuickGrid Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.AdditionalAttributes.get -> System.Collections.Generic.IReadOnlyDictionary? Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.AdditionalAttributes.set -> void -Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.AddUpdateSortByColumnAsync(Microsoft.AspNetCore.Components.QuickGrid.ColumnBase! column, Microsoft.AspNetCore.Components.QuickGrid.SortDirection direction = Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Auto) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.ChildContent.get -> Microsoft.AspNetCore.Components.RenderFragment? Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.ChildContent.set -> void Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Class.get -> string? @@ -117,16 +118,10 @@ Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.QuickGrid() -> vo Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.RefreshDataAsync() -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.ShowColumnOptionsAsync(Microsoft.AspNetCore.Components.QuickGrid.ColumnBase! column) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.SortByColumnAsync(Microsoft.AspNetCore.Components.QuickGrid.ColumnBase! column, Microsoft.AspNetCore.Components.QuickGrid.SortDirection direction = Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Auto) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.SortColumns.get -> System.Collections.Generic.IReadOnlyList!>! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Theme.get -> string? Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Theme.set -> void Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Virtualize.get -> bool Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.Virtualize.set -> void -Microsoft.AspNetCore.Components.QuickGrid.SortColumn -Microsoft.AspNetCore.Components.QuickGrid.SortColumn.Ascending.get -> bool -Microsoft.AspNetCore.Components.QuickGrid.SortColumn.Column.get -> Microsoft.AspNetCore.Components.QuickGrid.ColumnBase? -Microsoft.AspNetCore.Components.QuickGrid.SortColumn.Column.init -> void -Microsoft.AspNetCore.Components.QuickGrid.SortColumn.SortColumn() -> void Microsoft.AspNetCore.Components.QuickGrid.SortDirection Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Ascending = 1 -> Microsoft.AspNetCore.Components.QuickGrid.SortDirection Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Auto = 0 -> Microsoft.AspNetCore.Components.QuickGrid.SortDirection diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Unshipped.txt b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Unshipped.txt index a5806f90a9db..150645b0e3d2 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Unshipped.txt +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Unshipped.txt @@ -1,4 +1,14 @@ #nullable enable +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GetSortByProperties() -> System.Collections.Generic.IEnumerable!>! +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortColumns.get -> System.Collections.Generic.IReadOnlyList!>! +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortColumns.init -> void +Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.AddUpdateSortByColumnAsync(Microsoft.AspNetCore.Components.QuickGrid.ColumnBase! column, Microsoft.AspNetCore.Components.QuickGrid.SortDirection direction = Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Auto) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.HideColumnOptionsAsync() -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.RowClass.get -> System.Func? -Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.RowClass.set -> void \ No newline at end of file +Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.RowClass.set -> void +Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.SortColumns.get -> System.Collections.Generic.IReadOnlyList!>! +Microsoft.AspNetCore.Components.QuickGrid.SortColumn +Microsoft.AspNetCore.Components.QuickGrid.SortColumn.Ascending.get -> bool +Microsoft.AspNetCore.Components.QuickGrid.SortColumn.Column.get -> Microsoft.AspNetCore.Components.QuickGrid.ColumnBase? +Microsoft.AspNetCore.Components.QuickGrid.SortColumn.Column.init -> void +Microsoft.AspNetCore.Components.QuickGrid.SortColumn.SortColumn() -> void From ff989673eb6c61666e4db27559a410bc63e31338 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Tue, 8 Jul 2025 14:45:17 -0400 Subject: [PATCH 11/13] Remove these since they no longer exist --- .../src/PublicAPI.Shipped.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt index 1b580b50deff..141f5d81e02e 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt @@ -41,12 +41,7 @@ Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Ca Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.CancellationToken.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Count.get -> int? Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Count.init -> void -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GetSortByProperties() -> System.Collections.Generic.IReadOnlyCollection! Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GridItemsProviderRequest() -> void -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByAscending.get -> bool -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByAscending.init -> void -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByColumn.get -> Microsoft.AspNetCore.Components.QuickGrid.ColumnBase? -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByColumn.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.StartIndex.get -> int Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.StartIndex.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderResult From 402361de01b11c3ca632783d23c256bc14c20e25 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Wed, 9 Jul 2025 09:44:57 -0400 Subject: [PATCH 12/13] Restore existing API surface of GridItemsProviderRequest --- .../src/GridItemsProviderRequest.cs | 43 ++++++++++++++++++- .../src/PublicAPI.Shipped.txt | 5 +++ .../src/PublicAPI.Unshipped.txt | 2 +- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs index 4500d918e8ca..77d51e522a93 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs @@ -30,6 +30,24 @@ public readonly struct GridItemsProviderRequest /// public IReadOnlyList> SortColumns { get; init; } + /// + /// Specifies which column represents the sort order. + /// + /// Rather than inferring the sort rules manually, you should normally call either + /// or , since they also account for and automatically. + /// + [Obsolete("Use " + nameof(SortColumns) + " instead.")] + public ColumnBase? SortByColumn { get; init; } + + /// + /// Specifies the current sort direction. + /// + /// Rather than inferring the sort rules manually, you should normally call either + /// or , since they also account for and automatically. + /// + [Obsolete("Use " + nameof(SortColumns) + " instead.")] + public bool SortByAscending { get; init; } + /// /// A token that indicates if the request should be cancelled. /// @@ -41,6 +59,15 @@ internal GridItemsProviderRequest( StartIndex = startIndex; Count = count; SortColumns = sortColumns; + + var sortColumn = sortColumns.FirstOrDefault(); + + if (sortColumn != null) + { + SortByColumn = sortColumn.Column; + SortByAscending = sortColumn.Ascending; + } + CancellationToken = cancellationToken; } @@ -68,7 +95,21 @@ public IQueryable ApplySorting(IQueryable source) /// Produces a collection of (property name, direction) pairs representing the sorting rules. /// /// A collection of (property name, direction) pairs representing the sorting rules - public IEnumerable> GetSortByProperties() + [Obsolete("Use " + nameof(GetSortColumnProperties) + " instead.")] + public IReadOnlyCollection GetSortByProperties() => + SortByColumn?.SortBy?.ToPropertyList(SortByAscending) ?? Array.Empty(); + + /// + /// Produces a collection of collections representing the applied sort rules for the grid. + /// + /// + /// Each item in the returned sequence is a collection of property name and sort direction pairs that define one sorting expression. + /// The sequence reflects the sort precedence (first, second, etc.). + /// + /// + /// An of of representing the full sorting expression. + /// + public IEnumerable> GetSortColumnProperties() { foreach (var sortColumn in SortColumns) { diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt index 141f5d81e02e..1b580b50deff 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Shipped.txt @@ -41,7 +41,12 @@ Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Ca Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.CancellationToken.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Count.get -> int? Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.Count.init -> void +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GetSortByProperties() -> System.Collections.Generic.IReadOnlyCollection! Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GridItemsProviderRequest() -> void +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByAscending.get -> bool +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByAscending.init -> void +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByColumn.get -> Microsoft.AspNetCore.Components.QuickGrid.ColumnBase? +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortByColumn.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.StartIndex.get -> int Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.StartIndex.init -> void Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderResult diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Unshipped.txt b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Unshipped.txt index 150645b0e3d2..cf1b8e2114ac 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Unshipped.txt +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/PublicAPI.Unshipped.txt @@ -1,5 +1,5 @@ #nullable enable -Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GetSortByProperties() -> System.Collections.Generic.IEnumerable!>! +Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.GetSortColumnProperties() -> System.Collections.Generic.IEnumerable!>! Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortColumns.get -> System.Collections.Generic.IReadOnlyList!>! Microsoft.AspNetCore.Components.QuickGrid.GridItemsProviderRequest.SortColumns.init -> void Microsoft.AspNetCore.Components.QuickGrid.QuickGrid.AddUpdateSortByColumnAsync(Microsoft.AspNetCore.Components.QuickGrid.ColumnBase! column, Microsoft.AspNetCore.Components.QuickGrid.SortDirection direction = Microsoft.AspNetCore.Components.QuickGrid.SortDirection.Auto) -> System.Threading.Tasks.Task! From ca307682c1d22040d1313d92d93167dfd7fcbbc4 Mon Sep 17 00:00:00 2001 From: Adam Shortland Date: Wed, 9 Jul 2025 10:35:23 -0400 Subject: [PATCH 13/13] Instead of setting the obsolete property directly set a backing field and return the value out of that --- .../src/GridItemsProviderRequest.cs | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs index 77d51e522a93..1163a78d9619 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/GridItemsProviderRequest.cs @@ -37,7 +37,13 @@ public readonly struct GridItemsProviderRequest /// or , since they also account for and automatically. /// [Obsolete("Use " + nameof(SortColumns) + " instead.")] - public ColumnBase? SortByColumn { get; init; } + public ColumnBase? SortByColumn + { + get => _sortByColumn; + init => _sortByColumn = value; + } + + private readonly ColumnBase? _sortByColumn; /// /// Specifies the current sort direction. @@ -46,7 +52,13 @@ public readonly struct GridItemsProviderRequest /// or , since they also account for and automatically. /// [Obsolete("Use " + nameof(SortColumns) + " instead.")] - public bool SortByAscending { get; init; } + public bool SortByAscending + { + get => _sortByAscending; + init => _sortByAscending = value; + } + + private readonly bool _sortByAscending; /// /// A token that indicates if the request should be cancelled. @@ -60,12 +72,11 @@ internal GridItemsProviderRequest( Count = count; SortColumns = sortColumns; - var sortColumn = sortColumns.FirstOrDefault(); - - if (sortColumn != null) + if (sortColumns.Any()) { - SortByColumn = sortColumn.Column; - SortByAscending = sortColumn.Ascending; + var sortColumn = sortColumns[0]; + _sortByColumn = sortColumn.Column; + _sortByAscending = sortColumn.Ascending; } CancellationToken = cancellationToken;