Sorting in data grid respecting the culture specific sorting rules. #132

Closed
opened 2026-01-29 17:32:04 +00:00 by claunia · 3 comments
Owner

Originally created by @OndrejUzovic on GitHub (Jun 23, 2021).

Currently when data grid sorts text columns containing a string with diacritics, it displays it in incorrect order because it does not respect the culture specific sorting rules.

The solution for this problem could be to provide a 'Parameter' property Comparer (of type System.Collections.IComparer) into the data grid.
If the property is set then the comparer would be used in RadzenGrid.View as the second parameter when OrderBy(..) is called.

[Parameter]
public IComparer Comparer { get; set; }

public override IQueryable<TItem> View
    {
        get
        {
            var view = base.View.Where<TItem>(columns);

            if (!string.IsNullOrEmpty(orderBy))
            {
                if (typeof(TItem) == typeof(object))
                {
                    var firstItem = view.FirstOrDefault();
                    if (firstItem != null)
                    {
                       // comparer added
                        view = view.Cast(firstItem.GetType()).AsQueryable().OrderBy(orderBy, Comparer).Cast<TItem>();
                    }
                }
                else
                {
                    // comparer added
                    view = view.OrderBy(orderBy,, Comparer);
                }
            }

            return view;
        }
    }

Would you please consider this feature?

Originally created by @OndrejUzovic on GitHub (Jun 23, 2021). Currently when data grid sorts text columns containing a string with diacritics, it displays it in incorrect order because it does not respect the culture specific sorting rules. The solution for this problem could be to provide a 'Parameter' property Comparer (of type System.Collections.IComparer) into the data grid. If the property is set then the comparer would be used in RadzenGrid.View as the second parameter when OrderBy(..) is called. ``` [Parameter] public IComparer Comparer { get; set; } public override IQueryable<TItem> View { get { var view = base.View.Where<TItem>(columns); if (!string.IsNullOrEmpty(orderBy)) { if (typeof(TItem) == typeof(object)) { var firstItem = view.FirstOrDefault(); if (firstItem != null) { // comparer added view = view.Cast(firstItem.GetType()).AsQueryable().OrderBy(orderBy, Comparer).Cast<TItem>(); } } else { // comparer added view = view.OrderBy(orderBy,, Comparer); } } return view; } } ``` Would you please consider this feature?
Author
Owner

@enchev commented on GitHub (Jun 25, 2021):

Hey @OndrejUzovic ,

Maybe it will be better if we pass the current application culture instead exposing a property:
image

Not sure however how this will affect database sorting - should remain the same (performed by the database).

@enchev commented on GitHub (Jun 25, 2021): Hey @OndrejUzovic , Maybe it will be better if we pass the current application culture instead exposing a property: ![image](https://user-images.githubusercontent.com/5804953/123386720-a0d8a100-d59f-11eb-961e-0d4d0ec399cc.png) Not sure however how this will affect database sorting - should remain the same (performed by the database).
Author
Owner

@OndrejUzovic commented on GitHub (Jun 25, 2021):

Hi @enchev ,

thanks for your response. The problem with the CurrentCulture is that it would be difficult (maybe impossible) to use in cases if you have multiple users with different cultures (each user wants to see the column ordered according to his culture rules).

However the problem seems a bit more complex that I thought when I wrote my original proposal. The problem is, it is not enough to just expose the property for IComparer because the comparer would just get the whole TItem and would not know which column(s) shall be compared. The implementation of IComparer would have to store the reference to DataGrid and then use Query.OrderBy to resolve that - which seems somehow complex for a general solution.

So finally I came to the idea that maybe better than IComparer will be to expose CultureInfo in DataGrid. The culture specific string comparer would be created internally by DataGrid and used only if string columns shall be sorted.

Here is my final workaround solution which reflex this idea and I am currently using:
(It creates System.StringComparer for sorting string columns.)

public class RadzenGridImprove<TItem> : RadzenGrid<TItem>
    {
        [Parameter]
        public CultureInfo Culture { get; set; }

        public override IQueryable<TItem> View
        {
            get
            {
                IQueryable<TItem> result;

                var comparer = TryCreateComparer(Culture, Query.OrderBy);
                if (comparer != null)
                {
                    result = base.View.OrderBy(Query.OrderBy, comparer);
                }
                else
                {
                    result = base.View;
                }

                return result;
            }
        }

        private IComparer TryCreateComparer(CultureInfo culture, string ordering)
        {
            IComparer result = null;

            if (culture != null && !string.IsNullOrEmpty(ordering))
            {
                var words = ordering.Trim().Split(null);
                if (words.Length > 0)
                {
                    // Get the property name
                    var propertyName = words[0];

                    // If the property is string type then create the culture specific string comparer.
                    var propertyInfo = typeof(TItem).GetProperty(propertyName);
                    if (propertyInfo != null && propertyInfo.PropertyType == typeof(string))
                    {
                        result = StringComparer.Create(culture, CompareOptions.StringSort);
                    }
                }
            }

            return result;
        }
    }
@OndrejUzovic commented on GitHub (Jun 25, 2021): Hi @enchev , thanks for your response. The problem with the CurrentCulture is that it would be difficult (maybe impossible) to use in cases if you have multiple users with different cultures (each user wants to see the column ordered according to his culture rules). However the problem seems a bit more complex that I thought when I wrote my original proposal. The problem is, it is not enough to just expose the property for _IComparer_ because the comparer would just get the whole TItem and would not know which column(s) shall be compared. The implementation of _IComparer_ would have to store the reference to DataGrid and then use Query.OrderBy to resolve that - which seems somehow complex for a general solution. So finally I came to the idea that maybe better than _IComparer_ will be to expose CultureInfo in DataGrid. The culture specific string comparer would be created internally by DataGrid and used only if string columns shall be sorted. Here is my final workaround solution which reflex this idea and I am currently using: (It creates System.StringComparer for sorting string columns.) ``` public class RadzenGridImprove<TItem> : RadzenGrid<TItem> { [Parameter] public CultureInfo Culture { get; set; } public override IQueryable<TItem> View { get { IQueryable<TItem> result; var comparer = TryCreateComparer(Culture, Query.OrderBy); if (comparer != null) { result = base.View.OrderBy(Query.OrderBy, comparer); } else { result = base.View; } return result; } } private IComparer TryCreateComparer(CultureInfo culture, string ordering) { IComparer result = null; if (culture != null && !string.IsNullOrEmpty(ordering)) { var words = ordering.Trim().Split(null); if (words.Length > 0) { // Get the property name var propertyName = words[0]; // If the property is string type then create the culture specific string comparer. var propertyInfo = typeof(TItem).GetProperty(propertyName); if (propertyInfo != null && propertyInfo.PropertyType == typeof(string)) { result = StringComparer.Create(culture, CompareOptions.StringSort); } } } return result; } } ```
Author
Owner

@javiercampos commented on GitHub (Sep 8, 2021):

Hey @OndrejUzovic ,

Maybe it will be better if we pass the current application culture instead exposing a property:
image

Note that using CurrentCulture (which should be CurrentUICulture actually) might not be reliable enough because it's a thread local value and when changing it (using InvokeAsync or at events), the Blazor synchronization context doesn't pass it around (and it doesn't stick to a thread), so in dynamic culture scenarios that wouldn't be really reliable.

I've made a feature request here to actually have a Culture parameter on Radzen components directly (I was thinking on the templates, but could be used for this aswell), which should fallback to CurrentUICulture if not specified: this would work for the majority of cases (where the thread's and renderer culture is set by the ASP.NET localization middleware upon connection and it's not usually dynamically changed).

Not sure however how this will affect database sorting - should remain the same (performed by the database).

I'd leave the database ordering as is (performed by the database, or whatever provider you use), you typically use the database collation for those effects.

@javiercampos commented on GitHub (Sep 8, 2021): > Hey @OndrejUzovic , > > Maybe it will be better if we pass the current application culture instead exposing a property: > ![image](https://user-images.githubusercontent.com/5804953/123386720-a0d8a100-d59f-11eb-961e-0d4d0ec399cc.png) Note that using `CurrentCulture` (which should be `CurrentUICulture` actually) might not be reliable enough because it's a thread local value and when changing it (using `InvokeAsync` or at events), the Blazor synchronization context doesn't pass it around (and it doesn't stick to a thread), so in dynamic culture scenarios that wouldn't be really reliable. I've made a feature request [here](https://github.com/radzenhq/radzen-blazor/issues/206) to actually have a `Culture` parameter on Radzen components directly (I was thinking on the templates, but could be used for this aswell), which should fallback to `CurrentUICulture` if not specified: this would work for the majority of cases (where the thread's and renderer culture is set by the ASP.NET localization middleware upon connection and it's not usually dynamically changed). > Not sure however how this will affect database sorting - should remain the same (performed by the database). I'd leave the database ordering as is (performed by the database, or whatever provider you use), you typically use the database collation for those effects.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/radzen-blazor#132