XAML Fundamentals for Web & Mobile: Adding Custom Sorting Logic

Nick Randolph’s earlier post in this blog series covered the basics of sorting and grouping. The CollectionViewSource provides a wrapper around a data source that can indicate if the source is grouped and will maintain the selected item. Suppose you are familiar with CollectionViewSource from WPF. In that case, you may not be aware that the class no longer has functionality for sorting and grouping itself in UWP, but this can be achieved in the underlying source. The WinUI/Uno version follows the UWP functionality. 

Sorting Collections

.NET has a set of functionalities for querying collections, and they make up the System.Linq namespace. This adds several extension methods to standard .NET collection classes to allow querying, sorting, and grouping. LINQ stands for Language INtegrated Query, a declarative query syntax right in your C# code. You can perform operations using the query syntax or directly using the fluent OrderBy, GroupBy, etc. methods provided. 

LINQ

				
					var sortedAnimals = from animal in animals 

orderby animal.Name 
				
			

Fluent

				
					var sortedAnimals = animals.OrderBy(a => a.Name); 
				
			

When you are using intrinsic types such as Int32 (aliased as “int” in C#), there is a predictable behavior for sorting because these types implement the IComparable<T> interface. This interface defines a single method CompareTo which returns a value indicating whether the other instance is less than, greater than, or the same as the instance. This is relatively straightforward for numeric values but gets slightly more complex when considering strings. 

Ordering Strings

By default, the LINQ query syntax doesn’t support passing additional information to the orderby operation. For strings, it will use the invariant culture for ordering, which may not be the desired outcome. You can use the fluent LINQ syntax to pass a StringComparer argument to define the desired culture settings. This allows you to use either the current system culture or create a new instance from a specific CultureInfo e.g. 

				
					var comparer = StringComparer.Create(new CultureInfo(“fr-CA”)); 

var sortedStrings = strings.OrderBy(p=>p, comparer); 
				
			

That is great for a whole range of string operations, but what if you want to sort objects in a way that is not directly governed by a numeric id or an alphabetic string? The trick here is that comparer is an instance of IComparer, so you can create your own custom implementation to compare objects of any type in any way you choose. 

Our sample contains some data about fictional people. It is harder to sort because the names are not formatted consistently – some will appear as “FirstName LastName”; others will be reversed but with a comma separating them. We can create a CustomSorter class to handle this and then use it in a LINQ query. 

				
					public class CustomSorter : IComparer<Person> 
    { 
        public int Compare(Person x, Person y) 
        { 
            int result = GetSurnameFromDisplayName(x.DisplayName).CompareTo(GetSurnameFromDisplayName(y.DisplayName)); 
            return result; 
        } 

        private static string GetSurnameFromDisplayName(string displayName) 
        { 
            if(displayName.Contains(',')) 
            { 
                //surname first 
                var parts = displayName.Split(','); 
                if (parts.Length > 0) 
                    return parts[0].Trim(); 
            } 
            else 
            { 
                //surname last 
                var parts = displayName.Split(' '); 
                //return last name 
                return parts[parts.Length - 1].Trim(); 
            } 

            return string.Empty; 
        } 
    }
				
			

We have a custom method that extracts the surname from any given format. Then our Compare method uses this on both objects being compared to order the items. The values are not modified so that they will be displayed in their original form. 

We can sort the collection using the LINQ fluent syntax and assign it to a CollectionViewSource. We set the ItemsSource property on the ListView control in our XAML using x:Bind to the View property of the CollectionViewSource. 

				
					var sortQuery = rawPeople.OrderBy(p => p, sorter); 

SortedPeopleSource = new CollectionViewSource { Source = sortQuery }; 
				
			
About Uno Platform

For those new to Uno Platform – it allows for creation of pixel-perfect, single-source C# and XAML apps which run natively on Windows, iOS, Android, macOS, Linux and Web via WebAssembly. It offers Figma integration for design-development handoff, and a set of extensions to bootstrap your projects. Uno Platform is free and Open Source (Apache 2.0) and available on GitHub.

Next Steps

We’ve made the code sample available hereTo upgrade to the latest release of Uno Platform, please update your packages to 4.6 via your Visual Studio NuGet package manager! 

 If you are new to Uno Platform, following our official getting started guide is the best way to get started. (5 min to complete) You can also explore our samples and discover how to use Uno Platform to build your next desktop, mobile, and web apps. 

Tags:

Share this post: