W Internecie istnieje wiele rozwiązań, które próbują wypełnić to pozornie bardzo podstawowe pominięcie WPF. Jestem naprawdę zdezorientowany, jaki byłby „najlepszy” sposób. Na przykład ... Chcę, aby w nagłówku kolumny znajdowały się małe strzałki w górę / w dół, aby wskazać kierunek sortowania. Najwyraźniej istnieją trzy różne sposoby, aby to zrobić, niektóre za pomocą kodu, inne za pomocą znaczników, niektóre za pomocą kodu znaczników plus kod, a wszystkie wydają się raczej hackem.
Czy ktoś wcześniej napotkał ten problem i znalazł rozwiązanie, z którego jest całkowicie zadowolony? Wydaje się dziwne, że WPF nie posiada takiej podstawowej funkcjonalności WinForms i trzeba ją włamać.
Odpowiedzi:
Wszystko zależy tak naprawdę, jeśli używasz DataGrid z zestawu narzędzi WPF, istnieje wbudowane sortowanie, nawet sortowanie wielokolumnowe, które jest bardzo przydatne. Sprawdź więcej tutaj:
Blog Vincenta Sibalsa
Alternatywnie, jeśli używasz innej kontrolki, która nie obsługuje sortowania, polecam następujące metody:
Sortowanie niestandardowe Li Gao
Śledzony przez:
Szybsze sortowanie Li Gao
źródło
Napisałem zestaw załączonych właściwości, aby automatycznie sortować
GridView
, możesz to sprawdzić tutaj . Nie obsługuje strzałek w górę / w dół, ale można go łatwo dodać.<ListView ItemsSource="{Binding Persons}" IsSynchronizedWithCurrentItem="True" util:GridViewSort.AutoSort="True"> <ListView.View> <GridView> <GridView.Columns> <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" util:GridViewSort.PropertyName="Name"/> <GridViewColumn Header="First name" DisplayMemberBinding="{Binding FirstName}" util:GridViewSort.PropertyName="FirstName"/> <GridViewColumn Header="Date of birth" DisplayMemberBinding="{Binding DateOfBirth}" util:GridViewSort.PropertyName="DateOfBirth"/> </GridView.Columns> </GridView> </ListView.View> </ListView>
źródło
CollectionViewSource.GetDefaultView(MyList.ItemsSource).SortDescriptions.Add(new SortDescription("Number", ListSortDirection.Ascending));
nie działa.MSDN oferuje łatwy sposób sortowania według kolumn z glifami w górę / w dół. Przykład nie jest jednak kompletny - nie wyjaśniają, jak używać szablonów danych dla glifów. Poniżej znajduje się opis pracy z moim ListView. Działa to na .Net 4.
W ListView należy określić procedurę obsługi zdarzeń do uruchomienia dla kliknięcia GridViewColumnHeader. Mój ListView wygląda następująco:
<ListView Name="results" GridViewColumnHeader.Click="results_Click"> <ListView.View> <GridView> <GridViewColumn DisplayMemberBinding="{Binding Path=ContactName}"> <GridViewColumn.Header> <GridViewColumnHeader Content="Contact Name" Padding="5,0,0,0" HorizontalContentAlignment="Left" MinWidth="150" Name="ContactName" /> </GridViewColumn.Header> </GridViewColumn> <GridViewColumn DisplayMemberBinding="{Binding Path=PrimaryPhone}"> <GridViewColumn.Header> <GridViewColumnHeader Content="Contact Number" Padding="5,0,0,0" HorizontalContentAlignment="Left" MinWidth="150" Name="PrimaryPhone"/> </GridViewColumn.Header> </GridViewColumn> </GridView> </ListView.View> </ListView>
W swoim kodzie z tyłu skonfiguruj kod do obsługi sortowania:
// Global objects BindingListCollectionView blcv; GridViewColumnHeader _lastHeaderClicked = null; ListSortDirection _lastDirection = ListSortDirection.Ascending; // Header click event void results_Click(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); if (direction == ListSortDirection.Ascending) { headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowUp"] as DataTemplate; } else { headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowDown"] as DataTemplate; } // Remove arrow from previously sorted header if (_lastHeaderClicked != null && _lastHeaderClicked != headerClicked) { _lastHeaderClicked.Column.HeaderTemplate = null; } _lastHeaderClicked = headerClicked; _lastDirection = direction; } } // Sort code private void Sort(string sortBy, ListSortDirection direction) { blcv.SortDescriptions.Clear(); SortDescription sd = new SortDescription(sortBy, direction); blcv.SortDescriptions.Add(sd); blcv.Refresh(); }
Następnie w swoim XAML musisz dodać dwa DataTemplates, które zostały określone w metodzie sortowania:
<DataTemplate x:Key="HeaderTemplateArrowUp"> <DockPanel LastChildFill="True" Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GridViewColumnHeader}}}"> <Path x:Name="arrowUp" StrokeThickness="1" Fill="Gray" Data="M 5,10 L 15,10 L 10,5 L 5,10" DockPanel.Dock="Right" Width="20" HorizontalAlignment="Right" Margin="5,0,5,0" SnapsToDevicePixels="True"/> <TextBlock Text="{Binding }" /> </DockPanel> </DataTemplate> <DataTemplate x:Key="HeaderTemplateArrowDown"> <DockPanel LastChildFill="True" Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GridViewColumnHeader}}}"> <Path x:Name="arrowDown" StrokeThickness="1" Fill="Gray" Data="M 5,5 L 10,10 L 15,5 L 5,5" DockPanel.Dock="Right" Width="20" HorizontalAlignment="Right" Margin="5,0,5,0" SnapsToDevicePixels="True"/> <TextBlock Text="{Binding }" /> </DockPanel> </DataTemplate>
Użycie
DockPanel
withLastChildFill
set na true spowoduje, że glif będzie po prawej stronie nagłówka, a etykieta wypełni resztę miejsca. PowiązałemDockPanel
szerokośćActualWidth
z z,GridViewColumnHeader
ponieważ moje kolumny nie mają szerokości, co pozwala im automatycznie dopasowywać się do treści. Ustawiłem jednakMinWidth
s na kolumnach, aby glif nie zakrywał tytułu kolumny.TextBlock Text
Ustawiony jest pusty wiązania który wyświetla nazwę kolumny podaną w nagłówku.źródło
<Window.Resources>
lub<UserControl.Resources>
. HTHS;)headerClicked.Column.Header
(który jest tekstem nagłówka) jest równoważny z(headerClicked.Column.DisplayMemberBinding as Binding).Path.Path
(która jest ścieżką powiązania). Sortowanie według tekstu nagłówka nie działa. Bardzo dziwne.Używam MVVM, więc stworzyłem kilka własnych dołączonych właściwości, używając Thomasa jako odniesienia. Po kliknięciu nagłówka sortuje według jednej kolumny, przełączając się między Rosnąco a Malejąco. Sortuje od samego początku, używając pierwszej kolumny. I pokazuje glify w stylu Win7 / 8.
Zwykle wszystko, co musisz zrobić, to ustawić właściwość main na true (ale musisz jawnie zadeklarować GridViewColumnHeaders):
<Window xmlns:local="clr-namespace:MyProjectNamespace"> <Grid> <ListView local:App.EnableGridViewSort="True" ItemsSource="{Binding LVItems}"> <ListView.View> <GridView> <GridViewColumn DisplayMemberBinding="{Binding Property1}"> <GridViewColumnHeader Content="Prop 1" /> </GridViewColumn> <GridViewColumn DisplayMemberBinding="{Binding Property2}"> <GridViewColumnHeader Content="Prop 2" /> </GridViewColumn> </GridView> </ListView.View> </ListView> </Grid> <Window>
Jeśli chcesz posortować według innej właściwości niż wyświetlacz, musisz zadeklarować, że:
<GridViewColumn DisplayMemberBinding="{Binding Property3}" local:App.GridViewSortPropertyName="Property4"> <GridViewColumnHeader Content="Prop 3" /> </GridViewColumn>
Oto kod dołączonych właściwości, lubię być leniwy i umieszczać je w dostarczonym App.xaml.cs:
using System; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Data. using System.Windows.Media; using System.Windows.Media.Media3D; namespace MyProjectNamespace { public partial class App : Application { #region GridViewSort public static DependencyProperty GridViewSortPropertyNameProperty = DependencyProperty.RegisterAttached( "GridViewSortPropertyName", typeof(string), typeof(App), new UIPropertyMetadata(null) ); public static string GetGridViewSortPropertyName(GridViewColumn gvc) { return (string)gvc.GetValue(GridViewSortPropertyNameProperty); } public static void SetGridViewSortPropertyName(GridViewColumn gvc, string n) { gvc.SetValue(GridViewSortPropertyNameProperty, n); } public static DependencyProperty CurrentSortColumnProperty = DependencyProperty.RegisterAttached( "CurrentSortColumn", typeof(GridViewColumn), typeof(App), new UIPropertyMetadata( null, new PropertyChangedCallback(CurrentSortColumnChanged) ) ); public static GridViewColumn GetCurrentSortColumn(GridView gv) { return (GridViewColumn)gv.GetValue(CurrentSortColumnProperty); } public static void SetCurrentSortColumn(GridView gv, GridViewColumn value) { gv.SetValue(CurrentSortColumnProperty, value); } public static void CurrentSortColumnChanged( object sender, DependencyPropertyChangedEventArgs e) { GridViewColumn gvcOld = e.OldValue as GridViewColumn; if (gvcOld != null) { CurrentSortColumnSetGlyph(gvcOld, null); } } public static void CurrentSortColumnSetGlyph(GridViewColumn gvc, ListView lv) { ListSortDirection lsd; Brush brush; if (lv == null) { lsd = ListSortDirection.Ascending; brush = Brushes.Transparent; } else { SortDescriptionCollection sdc = lv.Items.SortDescriptions; if (sdc == null || sdc.Count < 1) return; lsd = sdc[0].Direction; brush = Brushes.Gray; } FrameworkElementFactory fefGlyph = new FrameworkElementFactory(typeof(Path)); fefGlyph.Name = "arrow"; fefGlyph.SetValue(Path.StrokeThicknessProperty, 1.0); fefGlyph.SetValue(Path.FillProperty, brush); fefGlyph.SetValue(StackPanel.HorizontalAlignmentProperty, HorizontalAlignment.Center); int s = 4; if (lsd == ListSortDirection.Ascending) { PathFigure pf = new PathFigure(); pf.IsClosed = true; pf.StartPoint = new Point(0, s); pf.Segments.Add(new LineSegment(new Point(s * 2, s), false)); pf.Segments.Add(new LineSegment(new Point(s, 0), false)); PathGeometry pg = new PathGeometry(); pg.Figures.Add(pf); fefGlyph.SetValue(Path.DataProperty, pg); } else { PathFigure pf = new PathFigure(); pf.IsClosed = true; pf.StartPoint = new Point(0, 0); pf.Segments.Add(new LineSegment(new Point(s, s), false)); pf.Segments.Add(new LineSegment(new Point(s * 2, 0), false)); PathGeometry pg = new PathGeometry(); pg.Figures.Add(pf); fefGlyph.SetValue(Path.DataProperty, pg); } FrameworkElementFactory fefTextBlock = new FrameworkElementFactory(typeof(TextBlock)); fefTextBlock.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Center); fefTextBlock.SetValue(TextBlock.TextProperty, new Binding()); FrameworkElementFactory fefDockPanel = new FrameworkElementFactory(typeof(StackPanel)); fefDockPanel.SetValue(StackPanel.OrientationProperty, Orientation.Vertical); fefDockPanel.AppendChild(fefGlyph); fefDockPanel.AppendChild(fefTextBlock); DataTemplate dt = new DataTemplate(typeof(GridViewColumn)); dt.VisualTree = fefDockPanel; gvc.HeaderTemplate = dt; } public static DependencyProperty EnableGridViewSortProperty = DependencyProperty.RegisterAttached( "EnableGridViewSort", typeof(bool), typeof(App), new UIPropertyMetadata( false, new PropertyChangedCallback(EnableGridViewSortChanged) ) ); public static bool GetEnableGridViewSort(ListView lv) { return (bool)lv.GetValue(EnableGridViewSortProperty); } public static void SetEnableGridViewSort(ListView lv, bool value) { lv.SetValue(EnableGridViewSortProperty, value); } public static void EnableGridViewSortChanged( object sender, DependencyPropertyChangedEventArgs e) { ListView lv = sender as ListView; if (lv == null) return; if (!(e.NewValue is bool)) return; bool enableGridViewSort = (bool)e.NewValue; if (enableGridViewSort) { lv.AddHandler( GridViewColumnHeader.ClickEvent, new RoutedEventHandler(EnableGridViewSortGVHClicked) ); if (lv.View == null) { lv.Loaded += new RoutedEventHandler(EnableGridViewSortLVLoaded); } else { EnableGridViewSortLVInitialize(lv); } } else { lv.RemoveHandler( GridViewColumnHeader.ClickEvent, new RoutedEventHandler(EnableGridViewSortGVHClicked) ); } } public static void EnableGridViewSortLVLoaded(object sender, RoutedEventArgs e) { ListView lv = e.Source as ListView; EnableGridViewSortLVInitialize(lv); lv.Loaded -= new RoutedEventHandler(EnableGridViewSortLVLoaded); } public static void EnableGridViewSortLVInitialize(ListView lv) { GridView gv = lv.View as GridView; if (gv == null) return; bool first = true; foreach (GridViewColumn gvc in gv.Columns) { if (first) { EnableGridViewSortApplySort(lv, gv, gvc); first = false; } else { CurrentSortColumnSetGlyph(gvc, null); } } } public static void EnableGridViewSortGVHClicked( object sender, RoutedEventArgs e) { GridViewColumnHeader gvch = e.OriginalSource as GridViewColumnHeader; if (gvch == null) return; GridViewColumn gvc = gvch.Column; if(gvc == null) return; ListView lv = VisualUpwardSearch<ListView>(gvch); if (lv == null) return; GridView gv = lv.View as GridView; if (gv == null) return; EnableGridViewSortApplySort(lv, gv, gvc); } public static void EnableGridViewSortApplySort( ListView lv, GridView gv, GridViewColumn gvc) { bool isEnabled = GetEnableGridViewSort(lv); if (!isEnabled) return; string propertyName = GetGridViewSortPropertyName(gvc); if (string.IsNullOrEmpty(propertyName)) { Binding b = gvc.DisplayMemberBinding as Binding; if (b != null && b.Path != null) { propertyName = b.Path.Path; } if (string.IsNullOrEmpty(propertyName)) return; } ApplySort(lv.Items, propertyName); SetCurrentSortColumn(gv, gvc); CurrentSortColumnSetGlyph(gvc, lv); } public static void ApplySort(ICollectionView view, string propertyName) { if (string.IsNullOrEmpty(propertyName)) return; ListSortDirection lsd = ListSortDirection.Ascending; if (view.SortDescriptions.Count > 0) { SortDescription sd = view.SortDescriptions[0]; if (sd.PropertyName.Equals(propertyName)) { if (sd.Direction == ListSortDirection.Ascending) { lsd = ListSortDirection.Descending; } else { lsd = ListSortDirection.Ascending; } } view.SortDescriptions.Clear(); } view.SortDescriptions.Add(new SortDescription(propertyName, lsd)); } #endregion public static T VisualUpwardSearch<T>(DependencyObject source) where T : DependencyObject { return VisualUpwardSearch(source, x => x is T) as T; } public static DependencyObject VisualUpwardSearch( DependencyObject source, Predicate<DependencyObject> match) { DependencyObject returnVal = source; while (returnVal != null && !match(returnVal)) { DependencyObject tempReturnVal = null; if (returnVal is Visual || returnVal is Visual3D) { tempReturnVal = VisualTreeHelper.GetParent(returnVal); } if (tempReturnVal == null) { returnVal = LogicalTreeHelper.GetParent(returnVal); } else { returnVal = tempReturnVal; } } return returnVal; } } }
źródło
Dokonałem adaptacji sposobu Microsoft, w którym nadpisuję
ListView
kontrolę, aby uzyskać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(); } }
((Binding)clickedHeader.Column.DisplayMemberBinding).Path.Path
Bit linii obsługuje przypadki, w których nazwy kolumn nie są takie same, jak ich ścieżki powiązań, czego nie robi metoda Microsoft.Chciałem przechwycić to
GridViewColumnHeader.Click
wydarzenie, żeby nie musieć o tym więcej myśleć, ale nie mogłem znaleźć sposobu, żeby to zrobić. W rezultacie dodaję w XAML dla każdegoSortableListView
:GridViewColumnHeader.Click="SortableListViewColumnHeaderClicked"
A następnie na każdym,
Window
który zawiera dowolną liczbęSortableListView
s, po prostu dodaj następujący kod:private void SortableListViewColumnHeaderClicked(object sender, RoutedEventArgs e) { ((Controls.SortableListView)sender).GridViewColumnHeaderClicked(e.OriginalSource as GridViewColumnHeader); }
Gdzie
Controls
jest tylko identyfikator XAML dla przestrzeni nazw, w której utworzonoSortableListView
formant.Tak więc zapobiega to duplikowaniu kodu po stronie sortowania, wystarczy pamiętać o obsłudze zdarzenia jak powyżej.
źródło
Jeśli masz widok listy i przekształcisz go w widok siatki, możesz łatwo ustawić klikalne nagłówki kolumn widoku siatki, robiąc to.
<Style TargetType="GridViewColumnHeader"> <Setter Property="Command" Value="{Binding CommandOrderBy}"/> <Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self},Path=Content}"/> </Style>
Następnie po prostu ustaw polecenie delegata w swoim kodzie.
public DelegateCommand CommandOrderBy { get { return new DelegateCommand(Delegated_CommandOrderBy); } } private void Delegated_CommandOrderBy(object obj) { throw new NotImplementedException(); }
Zakładam, że wszyscy wiecie, jak wykonać tutaj ICommand DelegateCommand. Pozwoliło mi to zachować klikanie całego widoku w ViewModel.
Dodałem to tylko po to, aby można było osiągnąć to samo na wiele sposobów. Nie pisałem kodu dodającego przyciski strzałek w nagłówku, ale byłoby to zrobione w stylu XAML, należałoby przeprojektować cały nagłówek, który JanDotNet ma w swoim kodzie.
źródło
Rozwiązanie, które podsumowuje wszystkie części robocze istniejących odpowiedzi i komentarzy, w tym szablony nagłówków kolumn:
Widok:
<ListView x:Class="MyNamspace.MyListView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" ItemsSource="{Binding Items}" GridViewColumnHeader.Click="ListViewColumnHeaderClick"> <ListView.Resources> <Style TargetType="Grid" x:Key="HeaderGridStyle"> <Setter Property="Height" Value="20" /> </Style> <Style TargetType="TextBlock" x:Key="HeaderTextBlockStyle"> <Setter Property="Margin" Value="5,0,0,0" /> <Setter Property="VerticalAlignment" Value="Center" /> </Style> <Style TargetType="Path" x:Key="HeaderPathStyle"> <Setter Property="StrokeThickness" Value="1" /> <Setter Property="Fill" Value="Gray" /> <Setter Property="Width" Value="20" /> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="Margin" Value="5,0,5,0" /> <Setter Property="SnapsToDevicePixels" Value="True" /> </Style> <DataTemplate x:Key="HeaderTemplateDefault"> <Grid Style="{StaticResource HeaderGridStyle}"> <TextBlock Text="{Binding }" Style="{StaticResource HeaderTextBlockStyle}" /> </Grid> </DataTemplate> <DataTemplate x:Key="HeaderTemplateArrowUp"> <Grid Style="{StaticResource HeaderGridStyle}"> <Path Data="M 7,3 L 13,3 L 10,0 L 7,3" Style="{StaticResource HeaderPathStyle}" /> <TextBlock Text="{Binding }" Style="{StaticResource HeaderTextBlockStyle}" /> </Grid> </DataTemplate> <DataTemplate x:Key="HeaderTemplateArrowDown"> <Grid Style="{StaticResource HeaderGridStyle}"> <Path Data="M 7,0 L 10,3 L 13,0 L 7,0" Style="{StaticResource HeaderPathStyle}" /> <TextBlock Text="{Binding }" Style="{StaticResource HeaderTextBlockStyle}" /> </Grid> </DataTemplate> </ListView.Resources> <ListView.View> <GridView ColumnHeaderTemplate="{StaticResource HeaderTemplateDefault}"> <GridViewColumn Header="Name" DisplayMemberBinding="{Binding NameProperty}" /> <GridViewColumn Header="Type" Width="45" DisplayMemberBinding="{Binding TypeProperty}"/> <!-- ... --> </GridView> </ListView.View> </ListView>
Kod za:
public partial class MyListView : ListView { GridViewColumnHeader _lastHeaderClicked = null; public MyListView() { InitializeComponent(); } private void ListViewColumnHeaderClick(object sender, RoutedEventArgs e) { GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader; if (headerClicked == null) return; if (headerClicked.Role == GridViewColumnHeaderRole.Padding) return; var sortingColumn = (headerClicked.Column.DisplayMemberBinding as Binding)?.Path?.Path; if (sortingColumn == null) return; var direction = ApplySort(Items, sortingColumn); if (direction == ListSortDirection.Ascending) { headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowUp"] as DataTemplate; } else { headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowDown"] as DataTemplate; } // Remove arrow from previously sorted header if (_lastHeaderClicked != null && _lastHeaderClicked != headerClicked) { _lastHeaderClicked.Column.HeaderTemplate = Resources["HeaderTemplateDefault"] as DataTemplate; } _lastHeaderClicked = headerClicked; } public static ListSortDirection ApplySort(ICollectionView view, string propertyName) { ListSortDirection direction = ListSortDirection.Ascending; if (view.SortDescriptions.Count > 0) { SortDescription currentSort = view.SortDescriptions[0]; if (currentSort.PropertyName == propertyName) { if (currentSort.Direction == ListSortDirection.Ascending) direction = ListSortDirection.Descending; else direction = ListSortDirection.Ascending; } view.SortDescriptions.Clear(); } if (!string.IsNullOrEmpty(propertyName)) { view.SortDescriptions.Add(new SortDescription(propertyName, direction)); } return direction; } }
źródło
Chciałem tylko dodać inny prosty sposób, w jaki ktoś może posortować element WPF ListView
void SortListView(ListView listView) { IEnumerable listView_items = listView.Items.SourceCollection; List<MY_ITEM_CLASS> listView_items_to_list = listView_items.Cast<MY_ITEM_CLASS>().ToList(); Comparer<MY_ITEM_CLASS> scoreComparer = Comparer<MY_ITEM_CLASS>.Create((first, second) => first.COLUMN_NAME.CompareTo(second.COLUMN_NAME)); listView_items_to_list.Sort(scoreComparer); listView.ItemsSource = null; listView.Items.Clear(); listView.ItemsSource = listView_items_to_list; }
źródło
Po wielu poszukiwaniach ostatecznie znalazłem proste tutaj https://www.wpf-tutorial.com/listview-control/listview-how-to-column-sorting/
private GridViewColumnHeader listViewSortCol = null; private SortAdorner listViewSortAdorner = null; private void GridViewColumnHeader_Click(object sender, RoutedEventArgs e) { GridViewColumnHeader column = (sender as GridViewColumnHeader); string sortBy = column.Tag.ToString(); if (listViewSortCol != null) { AdornerLayer.GetAdornerLayer(listViewSortCol).Remove(listViewSortAdorner); yourListView.Items.SortDescriptions.Clear(); } ListSortDirection newDir = ListSortDirection.Ascending; if (listViewSortCol == column && listViewSortAdorner.Direction == newDir) newDir = ListSortDirection.Descending; listViewSortCol = column; listViewSortAdorner = new SortAdorner(listViewSortCol, newDir); AdornerLayer.GetAdornerLayer(listViewSortCol).Add(listViewSortAdorner); yourListView.Items.SortDescriptions.Add(new SortDescription(sortBy, newDir)); }
Klasa:
public class SortAdorner : Adorner { private static Geometry ascGeometry = Geometry.Parse("M 0 4 L 3.5 0 L 7 4 Z"); private static Geometry descGeometry = Geometry.Parse("M 0 0 L 3.5 4 L 7 0 Z"); public ListSortDirection Direction { get; private set; } public SortAdorner(UIElement element, ListSortDirection dir) : base(element) { this.Direction = dir; } protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); if(AdornedElement.RenderSize.Width < 20) return; TranslateTransform transform = new TranslateTransform ( AdornedElement.RenderSize.Width - 15, (AdornedElement.RenderSize.Height - 5) / 2 ); drawingContext.PushTransform(transform); Geometry geometry = ascGeometry; if(this.Direction == ListSortDirection.Descending) geometry = descGeometry; drawingContext.DrawGeometry(Brushes.Black, null, geometry); drawingContext.Pop(); } }
Xaml
<GridViewColumn Width="250"> <GridViewColumn.Header> <GridViewColumnHeader Tag="Name" Click="GridViewColumnHeader_Click">Name</GridViewColumnHeader> </GridViewColumn.Header> <GridViewColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" ToolTip="{Binding Name}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn>
źródło
Spróbuj tego:
using System.ComponentModel; youtItemsControl.Items.SortDescriptions.Add(new SortDescription("yourFavoritePropertyFromItem",ListSortDirection.Ascending);
źródło