Browse Source

feat: enhance sorting functionality by mapping SortBy func references to property names

pull/25235/head
maliming 2 months ago
parent
commit
49a4aabe78
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 45
      framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs
  2. 61
      framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs

45
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<GridData<TListViewModel>> OnDataGridReadAsync(GridState<TListViewModel> 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<TableColumn>());
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)

61
framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs

@ -24,6 +24,12 @@ public partial class AbpMudExtensibleDataGrid<TItem> : ComponentBase
protected Regex ExtensionPropertiesRegex = new Regex(@"ExtraProperties\[(.*?)\]");
/// <summary>
/// Maps SortBy func references to their corresponding property names.
/// Used to resolve property names from MudBlazor SortDefinition.SortFunc.
/// </summary>
private readonly Dictionary<Func<TItem, object>, string> _sortFuncToPropertyMap = new();
[Parameter] public Func<GridState<TItem>, Task<GridData<TItem>>>? ServerData { get; set; }
[Parameter] public bool Loading { get; set; }
@ -59,6 +65,23 @@ public partial class AbpMudExtensibleDataGrid<TItem> : ComponentBase
}
}
/// <summary>
/// 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.
/// </summary>
/// <returns>The property name if found in the mapping, otherwise falls back to SortDefinition.SortBy.</returns>
public virtual string ResolveSortPropertyName(SortDefinition<TItem> 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<TItem> : 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<TItem> : 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<TItem, object>? 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<Func<TItem, object>>(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<Func<TItem, object>>(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<TItem, object>? GetExtensionPropertySortFunc(TableColumn column)
@ -233,11 +261,16 @@ public partial class AbpMudExtensibleDataGrid<TItem> : ComponentBase
}
var propertyName = match.Groups[1].Value;
return item =>
Func<TItem, object> 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)

Loading…
Cancel
Save