Best way to make WPF ListView/GridView sort on column-header clicking?

前端 未结 10 1149
感动是毒
感动是毒 2020-11-29 17:12

There are lots of solutions on the internet attempting to fill this seemingly very-basic omission from WPF. I\'m really confused as to what would be the \"best\" wa

10条回答
  •  星月不相逢
    2020-11-29 17:54

    I made an adaptation of the Microsoft way, where I override the ListView control to make a SortableListView:

    public partial class SortableListView : ListView
        {        
            private GridViewColumnHeader lastHeaderClicked = null;
            private ListSortDirection lastDirection = ListSortDirection.Ascending;       
    
            public void GridViewColumnHeaderClicked(GridViewColumnHeader clickedHeader)
            {
                ListSortDirection direction;
    
                if (clickedHeader != null)
                {
                    if (clickedHeader.Role != GridViewColumnHeaderRole.Padding)
                    {
                        if (clickedHeader != lastHeaderClicked)
                        {
                            direction = ListSortDirection.Ascending;
                        }
                        else
                        {
                            if (lastDirection == ListSortDirection.Ascending)
                            {
                                direction = ListSortDirection.Descending;
                            }
                            else
                            {
                                direction = ListSortDirection.Ascending;
                            }
                        }
    
                        string sortString = ((Binding)clickedHeader.Column.DisplayMemberBinding).Path.Path;
    
                        Sort(sortString, direction);
    
                        lastHeaderClicked = clickedHeader;
                        lastDirection = direction;
                    }
                }
            }
    
            private void Sort(string sortBy, ListSortDirection direction)
            {
                ICollectionView dataView = CollectionViewSource.GetDefaultView(this.ItemsSource != null ? this.ItemsSource : this.Items);
    
                dataView.SortDescriptions.Clear();
                SortDescription sD = new SortDescription(sortBy, direction);
                dataView.SortDescriptions.Add(sD);
                dataView.Refresh();
            }
        }
    

    The line ((Binding)clickedHeader.Column.DisplayMemberBinding).Path.Path bit handles the cases where your column names are not the same as their binding paths, which the Microsoft method does not do.

    I wanted to intercept the GridViewColumnHeader.Click event so that I wouldn't have to think about it anymore, but I couldn't find a way to to do. As a result I add the following in XAML for every SortableListView:

    GridViewColumnHeader.Click="SortableListViewColumnHeaderClicked"
    

    And then on any Window that contains any number of SortableListViews, just add the following code:

    private void SortableListViewColumnHeaderClicked(object sender, RoutedEventArgs e)
            {
                ((Controls.SortableListView)sender).GridViewColumnHeaderClicked(e.OriginalSource as GridViewColumnHeader);
            }
    

    Where Controls is just the XAML ID for the namespace in which you made the SortableListView control.

    So, this does prevent code duplication on the sorting side, you just need to remember to handle the event as above.

提交回复
热议问题