8

I have a listview for which the items gets added at run time in form of a grid with single/multiple columns. Now I need to get the sort working. Once the list view has items in it and they click on the column it should sort it on that column.

Below is the code for the listview

<ListView Name="lstValue" Margin="0,0,0,10"></ListView>

C# code where it populates the list view:

 case "Person":
                        dt = GetDataTable(GET_Person)
                        this.lstValue.View = gridview;
                        gridview.Columns.Add(new GridViewColumn { Header = "Number", 
                            DisplayMemberBinding = new Binding("Number") });
                        gridview.Columns.Add(new GridViewColumn { Header = "Name", 
                            DisplayMemberBinding = new Binding("Name") });
                        foreach(DataRow dr in dt.Rows)
                        {
                                                          this.lstValue.Items.Add(new ReportItem { Number = dr["Number"].ToString(),
                                Name = dr["Name"].ToString() });
                        }
                        break;

They should be able to sort on name or number.

user565992
  • 497
  • 2
  • 10
  • 17

2 Answers2

14

This link is the MSDN way. The main thing is to handle the click on the gridview column header.

<ListView x:Name='lv' Height="150" HorizontalAlignment="Center" 
  VerticalAlignment="Center" 
  GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler"
 >

And in the code:

GridViewColumnHeader _lastHeaderClicked = null;
ListSortDirection _lastDirection = ListSortDirection.Ascending;

void GridViewColumnHeaderClickedHandler(object sender,RoutedEventArgs e)
{
  GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
  ListSortDirection direction;

  if (headerClicked != null)
  {
      if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
      {
          if (headerClicked != _lastHeaderClicked)
          {
             direction = ListSortDirection.Ascending;
          }
          else
          {
             if (_lastDirection == ListSortDirection.Ascending)
             {
               direction = ListSortDirection.Descending;
             }
             else
             {
                 direction = ListSortDirection.Ascending;
             }
          }

          string header = headerClicked.Column.Header as string;
          Sort(header, direction);

          _lastHeaderClicked = headerClicked;
          _lastDirection = direction;
       }
    }
  }

 private void Sort(string sortBy, ListSortDirection direction)
 {
  ICollectionView dataView =
    CollectionViewSource.GetDefaultView(lv.ItemsSource);

  dataView.SortDescriptions.Clear();
  SortDescription sd = new SortDescription(sortBy, direction);
  dataView.SortDescriptions.Add(sd);
  dataView.Refresh();

}

Basically that's it. I did not include adding little direction glyphs on the column header to show the direction. If you want to see how to do that you can refer to the full tutorial (see link above).

Liz
  • 8,780
  • 2
  • 36
  • 40
  • ICollectionView dataView = CollectionViewSource.GetDefaultView(lstValue.ItemsSource); dataView.SortDescriptions.Clear(); -> when it runs this statement I am getting error "object reference not set to the instance of an object" error – user565992 Jun 11 '15 at 18:25
  • 2
    Oh sorry, I didn't take into account the fact that you are not using the ItemsSource property. In your case change the "CollectionViewSource...." stuff to lstValue.Items, and it should work. – Liz Jun 11 '15 at 19:20
  • I'm trying this sample and the click on the column header is detected but the listview is not sorted. I don´t get any error also. Any suggestion? – fedeteka Jan 19 '18 at 12:30
2

It's worth to node that accepted answer assumes the header names are equal to binding paths. Original MSDN takes paths form actual bindings. Here is basically the same code without dozen of redundant if/elses:

private GridViewColumnHeader lastHeaderClicked = null;
private ListSortDirection lastDirection = ListSortDirection.Ascending;

private void onHeaderClick(object sender, RoutedEventArgs e) {
    if (!(e.OriginalSource is GridViewColumnHeader ch)) return;
    var dir = ListSortDirection.Ascending;
    if (ch == lastHeaderClicked && lastDirection == ListSortDirection.Ascending)
        dir = ListSortDirection.Descending;
    sort(ch, dir);
    lastHeaderClicked = ch; lastDirection = dir;
}

private void sort(GridViewColumnHeader ch, ListSortDirection dir) {
    var bn = (ch.Column.DisplayMemberBinding as Binding)?.Path.Path;
    bn = bn ?? ch.Column.Header as string;
    var dv = CollectionViewSource.GetDefaultView(accessList.ItemsSource);
    dv.SortDescriptions.Clear();
    var sd = new SortDescription(bn, dir);
    dv.SortDescriptions.Add(sd);
    dv.Refresh();
}
Pawcio
  • 399
  • 5
  • 15