From 49a4aabe781ed8a82e6c9a61e73d387b0157dbe0 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 7 Apr 2026 14:41:13 +0800 Subject: [PATCH] feat: enhance sorting functionality by mapping SortBy func references to property names --- .../AbpMudCrudPageBase.cs | 45 +------------- .../AbpMudExtensibleDataGrid.razor.cs | 61 ++++++++++++++----- 2 files changed, 48 insertions(+), 58 deletions(-) diff --git a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs index a73c1b5ca6..cd97bc07dc 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs @@ -292,46 +292,6 @@ public abstract class AbpMudCrudPageBase< return sortBy; } - // When MudBlazor uses Func for SortBy, it returns an internal identifier (GUID) instead of property name - // We need to map it back to the actual property name from column.Data or column.PropertyName - - // Check if sortBy looks like an internal identifier (GUID format or contains lowercase letters and numbers) - // GUID format: 8-4-4-4-12 hexadecimal digits - var isGuidFormat = System.Guid.TryParse(sortBy, out _); - var looksLikeInternalId = isGuidFormat || (sortBy.Length > 0 && char.IsLower(sortBy[0]) && sortBy.Any(char.IsDigit)); - - if (looksLikeInternalId) - { - // Get all sortable columns that are not extension properties, in order - var sortableColumns = columns - .Where(c => c.Sortable && - !string.IsNullOrEmpty(c.Data) && - !c.Data.StartsWith("ExtraProperties[")) - .ToList(); - - // Since we can't reliably match GUID to specific column, - // we use the first sortable column's property name - // This works when there's only one sortable column being sorted - // For multiple columns, this is a limitation - we'd need to track the mapping - var sortableColumn = sortableColumns.FirstOrDefault(); - - if (sortableColumn != null) - { - // Prefer PropertyName if available, otherwise use Data - if (!string.IsNullOrEmpty(sortableColumn.PropertyName)) - { - return sortableColumn.PropertyName; - } - - if (!string.IsNullOrEmpty(sortableColumn.Data)) - { - return sortableColumn.Data; - } - } - } - - // If sortBy doesn't look like an internal identifier, return it as-is - // It might already be the correct property name return sortBy; } @@ -371,11 +331,8 @@ public abstract class AbpMudCrudPageBase< protected virtual async Task> OnDataGridReadAsync(GridState state) { - // Map sort field names from MudBlazor to actual property names - // When using Func for SortBy, MudBlazor returns internal identifiers (GUIDs) instead of property names - var columns = TableColumns.GetOrAdd(GetType().FullName!, () => new List()); CurrentSorting = state.SortDefinitions - .Select(s => MapSortFieldToPropertyName(s.SortBy, columns) + (s.Descending ? " DESC" : "")) + .Select(s => _dataGrid.ResolveSortPropertyName(s) + (s.Descending ? " DESC" : "")) .JoinAsString(","); CurrentPage = state.Page + 1; if (state.PageSize > 0) diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs index 7dad0c4ad3..14f834b10e 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs @@ -24,6 +24,12 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase protected Regex ExtensionPropertiesRegex = new Regex(@"ExtraProperties\[(.*?)\]"); + /// + /// Maps SortBy func references to their corresponding property names. + /// Used to resolve property names from MudBlazor SortDefinition.SortFunc. + /// + private readonly Dictionary, string> _sortFuncToPropertyMap = new(); + [Parameter] public Func, Task>>? ServerData { get; set; } [Parameter] public bool Loading { get; set; } @@ -59,6 +65,23 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase } } + /// + /// Resolves the property name for a given SortDefinition by matching its SortFunc reference. + /// When MudBlazor uses Func for SortBy on TemplateColumn, it returns an internal GUID identifier + /// instead of the property name. This method looks up the original property name from the + /// registered sort function mapping. + /// + /// The property name if found in the mapping, otherwise falls back to SortDefinition.SortBy. + public virtual string ResolveSortPropertyName(SortDefinition sortDefinition) + { + if (sortDefinition.SortFunc != null && _sortFuncToPropertyMap.TryGetValue(sortDefinition.SortFunc, out var propertyName)) + { + return propertyName; + } + + return sortDefinition.SortBy; + } + protected virtual RenderFragment RenderCustomTableColumnComponent(Type type, object data) { return (builder) => @@ -176,8 +199,7 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase return null; } - // Return PropertyName if available, otherwise use Data - // PropertyName is preferred as it's explicitly set for sorting + // Determine the property path for sorting string? propertyPath = null; if (!string.IsNullOrEmpty(column.PropertyName)) { @@ -193,30 +215,36 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase return null; } - // Create a property accessor lambda that MudBlazor can understand - // This uses the property name from propertyPath to build a proper expression var properties = propertyPath.Split('.'); - + // Build a lambda expression that directly accesses the property - // This allows MudBlazor to extract the property name for sorting var parameter = System.Linq.Expressions.Expression.Parameter(typeof(TItem), "x"); System.Linq.Expressions.Expression expression = parameter; - + + Func? sortFunc = null; foreach (var prop in properties) { var propertyInfo = expression.Type.GetProperty(prop, BindingFlags.Public | BindingFlags.Instance); if (propertyInfo == null) { // Fallback to GetPropertyValue if property not found - return item => GetPropertyValue(item, propertyPath); + sortFunc = item => GetPropertyValue(item, propertyPath); + break; } expression = System.Linq.Expressions.Expression.Property(expression, propertyInfo); } - - // Convert to object and create lambda - var convertExpression = System.Linq.Expressions.Expression.Convert(expression, typeof(object)); - var lambda = System.Linq.Expressions.Expression.Lambda>(convertExpression, parameter); - return lambda.Compile(); + + if (sortFunc == null) + { + var convertExpression = System.Linq.Expressions.Expression.Convert(expression, typeof(object)); + var lambda = System.Linq.Expressions.Expression.Lambda>(convertExpression, parameter); + sortFunc = lambda.Compile(); + } + + // Register the mapping so we can resolve property name from SortDefinition.SortFunc later + _sortFuncToPropertyMap[sortFunc] = propertyPath; + + return sortFunc; } protected virtual Func? GetExtensionPropertySortFunc(TableColumn column) @@ -233,11 +261,16 @@ public partial class AbpMudExtensibleDataGrid : ComponentBase } var propertyName = match.Groups[1].Value; - return item => + Func sortFunc = item => { var entity = item as IHasExtraProperties; return entity?.GetProperty(propertyName) ?? string.Empty; }; + + // Register the mapping so we can resolve property name from SortDefinition.SortFunc later + _sortFuncToPropertyMap[sortFunc] = propertyName; + + return sortFunc; } protected virtual Color GetColor(object? color)