Sorting in Xamarin ListView (SfListView)

17 Aug 202113 minutes to read

The SfListView supports sorting the data either in ascending or descending order by using DataSource.SortDescriptors property and by using the custom logic.

NOTE

When ItemsSource changed for ListView, DataSource.SortDescriptors will be cleared by default. You need to add DataSource.SortDescriptors again after changing ItemsSource if you want to retain sorting in listview.

NOTE

To sort the newly added listview items at runtime, set the SfListView.DataSource.LiveDataUpdateMode to LiveDataUpdateMode.AllowDataShaping. To learn more details about the LiveDataUpdateMode, refer to here.

Programmatic sorting

Sorting the data by creating the SortDescriptor with required property name and direction and adding it into the DataSource.SortDescriptors property.

SortDescriptor object holds the following three properties:

<ContentPage xmlns:syncfusion="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
             xmlns:data="clr-namespace:Syncfusion.DataSource;assembly=Syncfusion.DataSource.Portable">
  <sync:SfListView x:Name="listView">
            <sync:SfListView.DataSource>
                <data:DataSource>
                    <data:DataSource.SortDescriptors>
                        <data:SortDescriptor PropertyName="ContactName" Direction="Ascending"/>
                    </data:DataSource.SortDescriptors>
                </data:DataSource>
            </sync:SfListView.DataSource>
  </syncfusion:SfListView>
</ContentPage>
listView.DataSource.SortDescriptors.Add(new SortDescriptor()
{
  PropertyName = "ContactName",
  Direction = ListSortDirection.Ascending,
}); 
listView.RefreshView();

NOTE

It is mandatory to specify the PropertyName of SortDescriptor.

Sort items in listview

Custom sorting

Sort the items based on the custom logic and it can be applied to either SfListView.DataSource.SortComparer property or SortDescriptor.Comparer which is added into theĀ DataSource.SortDescriptors collection.

You can download the entire sample code from the github.

NOTE

If the PropertyName in the SortDescriptor and GroupDescriptor are same then, GroupResult will be passed as parameters for the SortDescriptor.Comparer. Otherwise data objects are passed. To sort the data items alone, set the different PropertyName in both SortDescriptor and GroupDescriptor properties.

<ContentPage xmlns:syncfusion="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
             xmlns:data="clr-namespace:Syncfusion.DataSource;assembly=Syncfusion.DataSource.Portable">
  <ContentPage.Resources>
    <ResourceDictionary>
      <local:CustomSortComparer x:Key="CustomSortComparer" />
    </ResourceDictionary>
  </ContentPage.Resources>
  <syncfusion:SfListView x:Name="listView"
    <syncfusion:SfListView.DataSource>
      <data:DataSource>
        <data:DataSource.SortDescriptors>
          <data:SortDescriptor Comparer="{StaticResource CustomSortComparer}"/>
        </data:DataSource.SortDescriptors>
      </data:DataSource>
    </syncfusion:SfListView.DataSource>
  </syncfusion:SfListView>
</ContentPage>
listView.DataSource.SortDescriptors.Add(new SortDescriptor()
{
  Comparer = new CustomSortComparer()
});
public class CustomSortComparer : IComparer<object>
{
  public int Compare(object x, object y)
  {
     if (x.GetType() == typeof(ListViewContactsInfo))
     {
        var xitem = (x as ListViewContactsInfo).ContactName;
        var yitem = (y as ListViewContactsInfo).ContactName;

        if (xitem.Length > yitem.Length)
        {
           return 1;
        }
        else if (xitem.Length < yitem.Length)
        {
           return -1;
        }
        else
        {
           if (string.Compare(xitem, yitem) == -1)
               return -1;
           else if (string.Compare(xitem, yitem) == 1)
               return 1;
        }
     }

     return 0;
   }
}

For more information about custom sorting of groups, please refer the documentation here.

Sort the items on header tapped

To apply the sorting when tapping the header, handle the ItemTapped event of the SfListView.

<ContentPage xmlns:syncfusion="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
             xmlns:data="clr-namespace:Syncfusion.DataSource;assembly=Syncfusion.DataSource.Portable">
  <syncfusion:SfListView x:Name="listView" ItemSize="60"
                        ItemsSource="{Binding customerDetails}" 
                        ItemTapped="ListView_ItemTapped" 
                        IsStickyHeader="True">
    <syncfusion:SfListView.HeaderTemplate>
      <DataTemplate>
        <ViewCell>
          <ViewCell.View>
            <StackLayout BackgroundColor="Teal">
              <Label TextColor="White" FontSize="20" FontAttributes="Bold" Text="CustomerDetails" />
            </StackLayout>
          </ViewCell.View>
        </ViewCell>
      </DataTemplate>
    </syncfusion:SfListView.HeaderTemplate>
  </syncfusion:SfListView>
</ContentPage>
listView = new SfListView();
listView.ItemsSource = viewModel.customerDetails;
listView.ItemSize = 60;
listView.ItemTapped += ListView_ItemTapped;
listView.IsStickyHeader = true;
listView.HeaderTemplate = new DataTemplate(() => 
{
  var stackLayout = new StackLayout { BackgroundColor = Color.Teal };
  var label = new Label { Text = "CustomerDetails", TextColor = Color.White, 
                          FontAttributes = FontAttributes.Bold, FontSize = 20 };
  stackLayout.Children.Add(label);
  return stackLayout;
});

When the ItemTapped event is raised for the Header, add the SortDescriptor and refresh the view.

private void ListView_ItemTapped(object sender, Syncfusion.ListView.XForms.ItemTappedEventArgs e)
{
  //Applying sorting to the underlying data when the header item is tapped.
  if (e.ItemType == ItemType.Header && listView.IsStickyHeader)
  {
    listView.DataSource.SortDescriptors.Clear();
    listView.DataSource.SortDescriptors.Add(new SortDescriptor()
    {
      PropertyName = "ContactName",
      Direction = ListSortDirection.Ascending
    });
  }
}

Sort the items along with grouping

The SfListView allows sorting the items along with grouping by adding the DataSource.GroupDescriptors and the DataSource.SortDescriptors with required property name.

Sorting with grouping by year

Sorting the items along with grouping by using KeySelector based on retuning the year value of the data-time property.

<ContentPage xmlns:syncfusion="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
             xmlns:data="clr-namespace:Syncfusion.DataSource;assembly=Syncfusion.DataSource.Portable">
  <ContentPage.Content>
    <syncfusion:SfListView x:Name="listView" ItemsSource="{Binding Items}" ItemSize="50">
      <syncfusion:SfListView.GroupHeaderTemplate>
        <DataTemplate>
		  <Grid>
          <Label Text= "{Binding Key}" BackgroundColor="Teal" FontAttributes="Bold" TextColor="White"/>
		  </Grid>
        </DataTemplate>
      </syncfusion:SfListView.GroupHeaderTemplate>
    </syncfusion:SfListView>
  </ContentPage.Content>
</ContentPage>
var listView = new SfListView();
listView.ItemSize = 50;
listView.ItemsSource = viewModel.Items;
listView.GroupHeaderTemplate = new DataTemplate(() => 
{
   var grid = new Grid();
   var headerLabel = new Label
   {
   TextColor = Color.White,
   FontAttributes = FontAttributes.Bold,
   BackgroundColor=Color.Teal
   };
   headerLabel.SetBinding(Label.TextProperty, new Binding("key"));
   grid.Children.Add(headerLabel);
   return grid;
});
listView.DataSource.GroupDescriptors.Add(new GroupDescriptor()
{
  PropertyName = "DateOfBirth",
  KeySelector = (object obj1) =>
  {
   var item = (obj1 as Contacts);
   return item.DateOfBirth.Year;
  },
});
this.listView.DataSource.SortDescriptors.Add(new SortDescriptor()
{
  PropertyName = "DateOfBirth",
  Direction = ListSortDirection.Ascending
});

The following screenshot shows the output when items are sorted by year. Download the entire source code from GitHub here

Custom sort by year in listview

Sorting with grouping by month and year

Sorting the items along with grouping by using KeySelector based on returning the month and year value of the data-time property.

<ContentPage xmlns:syncfusion="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
             xmlns:data="clr-namespace:Syncfusion.DataSource;assembly=Syncfusion.DataSource.Portable">
  <ContentPage.Content>
    <syncfusion:SfListView x:Name="listView">
      <syncfusion:SfListView.DataSource>
        <data:DataSource>
        <data:DataSource.GroupDescriptors>
            <data:GroupDescriptor PropertyName="ContactName" />
          </data:DataSource.GroupDescriptors>
          <data:DataSource.SortDescriptors>
            <data:SortDescriptor PropertyName="ContactName" Direction="Ascending"/>
          </data:DataSource.SortDescriptors>
        </data:DataSource>
      </syncfusion:SfListView.DataSource>
    </syncfusion:SfListView>
  </ContentPage.Content>
</ContentPage>
public partial class MainPage : ContentPage
{
   public MainPage()
   {
       InitializeComponent();
       listView.DataSource.GroupDescriptors.Add(new GroupDescriptor()
       {
           PropertyName = "DateOfBirth",
           KeySelector = (object obj1) =>
           {
               var item = (obj1 as Contacts);
               return item.DateOfBirth.Month + "/" + item.DateOfBirth.Year;
           },
           Comparer = new CustomGroupComparer()
       });
       this.listView.DataSource.SortDescriptors.Add(new SortDescriptor()
       {
           PropertyName = "DateOfBirth",
           Direction = ListSortDirection.Ascending
       });
   }
}

The following screenshot shows the output when items are sorted by month and year.

Custom sort by month in listview

NOTE

You can refer to our Xamarin ListView feature tour page for its groundbreaking feature representations. You can also explore our Xamarin.Forms ListView example to know how to render set of data items with Xamarin.Forms views or custom templates.