How to sort ListView by selected column?

Charles He-MSFT 96 Reputation points Microsoft Employee
2020-02-25T08:03:30.603+00:00

Source thread: how to sort list view with different dataTemplate (int, bool, string, ...), answered by Alex Li-MSFT.

I have a ListView control and I want to sort all the items in the list when user click on specific column header, how to achieve it?

Here is my XAML code:

<ListView ItemsSource="{Binding}" x:Name="listViewControl">  
  
  <ListView.View>  
    <GridView AllowsColumnReorder="True">  
        
      <GridViewColumn>  
        <GridViewColumn.CellTemplate>  
          <DataTemplate>  
            <TextBlock Text="{Binding Path=SomeInteger}"/>  
          </DataTemplate>  
        </GridViewColumn.CellTemplate>  
      </GridViewColumn>  
  
      <GridViewColumn>  
        <GridViewColumn.CellTemplate>  
          <DataTemplate>  
            <TextBlock Text="{Binding Path=SomeString}"/>  
          </DataTemplate>  
        </GridViewColumn.CellTemplate>  
      </GridViewColumn>  
  
      <GridViewColumn>  
        <GridViewColumn.CellTemplate>  
          <DataTemplate>  
            <CheckBox  IsChecked="{Binding SomeBool}"/>  
          </DataTemplate>  
        </GridViewColumn.CellTemplate>  
      </GridViewColumn>  
  
      <GridViewColumn Header="Category" Width="120">  
        <GridViewColumn.CellTemplate>  
          <DataTemplate>  
            <ComboBox ItemsSource="{Binding ElementName=mainWindow, Path=StringList}"  
                      SelectedItem="{Binding Path=SomeString}"/>  
          </DataTemplate>  
        </GridViewColumn.CellTemplate>  
      </GridViewColumn>  
  
</ListView>  
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,783 questions
0 comments No comments
{count} votes

Accepted answer
  1. Alex Li-MSFT 1,096 Reputation points
    2020-02-25T08:15:40.697+00:00

    Hi,

    Welcome to our Microsoft Q&A platform!

    You can use my demo:

     public partial class MainWindow : Window  
        {  
            ObservableCollection<MyClass> list = new ObservableCollection<MyClass>();  
            public MainWindow()  
            {  
                InitializeComponent();  
                list.Add(new MyClass() { SomeBool = false, SomeInteger = 1, SomeString = "3" });  
                list.Add(new MyClass() { SomeBool = false, SomeInteger = 2, SomeString = "2" });  
                list.Add(new MyClass() { SomeBool = true, SomeInteger = 3, SomeString = "3" });  
                this.DataContext = list;  
            }  
      
            private void ListViewControl_Click(object sender, RoutedEventArgs e)  
            {  
                  
                if (e.OriginalSource is GridViewColumnHeader)  
                {  
      
                    GridViewColumn clickedColumn = (e.OriginalSource as GridViewColumnHeader).Column;  
                  
                    string bindingProperty=null;  
                    if (clickedColumn != null)  
                    {  
                        if (clickedColumn.Header.ToString() == "column1")  
                        {  
                             bindingProperty = "SomeInteger";  
                        }  
                        if (clickedColumn.Header.ToString() == "column2")  
                        {  
                            bindingProperty = "SomeString";  
                        }  
                        if (clickedColumn.Header.ToString() == "column3")  
                        {  
                            bindingProperty = "SomeBool";  
                        }  
                        SortDescriptionCollection sdc = listViewControl.Items.SortDescriptions;  
                        ListSortDirection sortDirection = ListSortDirection.Ascending;  
                        if (sdc.Count > 0)  
                        {  
                            SortDescription sd = sdc[0];  
                            sortDirection = (ListSortDirection)((((int)sd.Direction) + 1) % 2);  
                            sdc.Clear();  
                        }  
                        sdc.Add(new SortDescription(bindingProperty, sortDirection));  
                    }  
                }  
            }  
             
        }  
          
        
        public class MyClass  
        {  
            public int SomeInteger { get; set; }  
            public string SomeString { get; set; }  
            public bool SomeBool { get; set; }  
        }  
    

    Xaml:

    <Grid>  
            <ListView  ItemsSource="{Binding}"  x:Name="listViewControl" GridViewColumnHeader.Click="ListViewControl_Click">  
      
                <ListView.View>  
                    <GridView AllowsColumnReorder="True">  
      
                        <GridViewColumn Header="column1" >  
                            <GridViewColumn.CellTemplate>  
                                <DataTemplate>  
                                    <TextBlock Text="{Binding Path=SomeInteger}" />  
                                </DataTemplate>  
                            </GridViewColumn.CellTemplate>  
                        </GridViewColumn>  
      
                        <GridViewColumn Header="column2">  
                            <GridViewColumn.CellTemplate>  
                                <DataTemplate>  
                                    <TextBlock Text="{Binding Path=SomeString}"/>  
                                </DataTemplate>  
                            </GridViewColumn.CellTemplate>  
                        </GridViewColumn>  
      
                        <GridViewColumn Header="column3">  
                            <GridViewColumn.CellTemplate>  
                                <DataTemplate>  
                                    <CheckBox  IsChecked="{Binding SomeBool}"/>  
                                </DataTemplate>  
                            </GridViewColumn.CellTemplate>  
                        </GridViewColumn>  
      
                        <GridViewColumn Header="Category" Width="120">  
                            <GridViewColumn.CellTemplate>  
                                <DataTemplate>  
                                    <ComboBox ItemsSource="{Binding ElementName=mainWindow, Path=StringList}"  
                          SelectedItem="{Binding Path=SomeString}"/>  
                                </DataTemplate>  
                            </GridViewColumn.CellTemplate>  
      
                        </GridViewColumn>  
                        </GridView>  
                </ListView.View>  
            </ListView>  
        </Grid>  
    

    3501-1544672.gif

    Thanks.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,326 Reputation points
    2020-03-03T09:11:14.01+00:00

    Try another approach.

    XAML:

    <Window x:Class="WpfApp1.Window97"  
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
            xmlns:local="clr-namespace:WpfApp1"  
            mc:Ignorable="d"  
            Title="Window97" Height="450" Width="800">  
      <Window.Resources>  
        <local:Window97VM x:Key="vm"/>  
      </Window.Resources>  
      <Grid DataContext="{StaticResource vm}">  
        <ListView ItemsSource="{Binding SimpleLayerView}"   
                IsSynchronizedWithCurrentItem="True">  
          <ListView.View>  
            <GridView AllowsColumnReorder="True">  
              <GridView.ColumnHeaderTemplate>  
                <DataTemplate>  
                  <Button Content="{Binding}"   
                        Command="{Binding Cmd, Source={StaticResource vm}}"  
                        CommandParameter="{Binding}"/>  
                </DataTemplate>  
              </GridView.ColumnHeaderTemplate>  
              <GridViewColumn Header="LayerOrder">  
                <GridViewColumn.CellTemplate>  
                  <DataTemplate>  
                    <TextBlock Text="{Binding LayerOrder}"/>  
                  </DataTemplate>  
                </GridViewColumn.CellTemplate>  
              </GridViewColumn>  
              <GridViewColumn Header="SomeInteger">  
                <GridViewColumn.CellTemplate>  
                  <DataTemplate>  
                    <TextBlock Text="{Binding SomeInteger}"/>  
                  </DataTemplate>  
                </GridViewColumn.CellTemplate>  
              </GridViewColumn>  
              <GridViewColumn Header="SomeBool">  
                <GridViewColumn.CellTemplate>  
                  <DataTemplate>  
                    <CheckBox IsChecked="{Binding SomeBool}"/>  
                  </DataTemplate>  
                </GridViewColumn.CellTemplate>  
              </GridViewColumn>  
            </GridView>  
          </ListView.View>  
        </ListView>  
      </Grid>  
    </Window>  
    

    And ViewModel:

    using System;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System.Windows;  
    using System.Windows.Data;  
    using System.Windows.Input;  
      
    namespace WpfApp1  
    {  
     
      public class Window97VM  
      {  
        public Window97VM()  
        {  
          Random rnd = new Random();  
          ObservableCollection<Data> l = new ObservableCollection<Data>();  
          for (int i = 0; i < 11; i++)  
            l.Add(new Data() { LayerOrder = $"Order {i}", SomeBool = rnd.NextDouble() > 0.5, SomeInteger = rnd.Next(1, 100) });  
          cvs.Source = l;  
        }  
        private CollectionViewSource cvs = new CollectionViewSource();  
        public ICollectionView SimpleLayerView { get => cvs.View; }  
        public ICommand Cmd { get => new RelayCommand(CmdExec); }  
        private void CmdExec(Object obj)  
        {  
          string bindingProperty = obj.ToString();  
          ListSortDirection sortDirection = ListSortDirection.Ascending;  
          if (SimpleLayerView.SortDescriptions.Count > 0 && SimpleLayerView.SortDescriptions[0].Direction == sortDirection)  
            sortDirection = ListSortDirection.Descending;  
          SimpleLayerView.SortDescriptions.Clear();  
          SimpleLayerView.SortDescriptions.Add(new SortDescription(bindingProperty, sortDirection));  
        }  
        public class Data  
        {  
          public string LayerOrder { get; set; }  
          public int SomeInteger { get; set; }  
          public bool SomeBool { get; set; }  
        }  
      }  
    }  
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.