Trier La Collecte Observable C#
j'ai en dessous de ObservableCollection<string>
. Je dois trier par ordre alphabétique.
private ObservableCollection<string> _animals = new ObservableCollection<string>
{
"Cat", "Dog", "Bear", "Lion", "Mouse",
"Horse", "Rat", "Elephant", "Kangaroo", "Lizard",
"Snake", "Frog", "Fish", "Butterfly", "Human",
"Cow", "Bumble Bee"
};
j'ai essayé _animals.OrderByDescending
. mais je ne sais pas comment l'utiliser correctement.
_animals.OrderByDescending(a => a.<what_is_here_?>);
Comment faire ?
9 réponses
Introduction
fondamentalement, s'il y a un besoin d'afficher une collection triée, s'il vous plaît envisager d'utiliser la classe CollectionViewSource
: assignez ("bind") sa propriété Source
à la collection source - une instance de la classe ObservableCollection<T>
.
l'idée est que CollectionViewSource
classe fournit une instance de la CollectionView
classe . C'est une sorte de "projection" de la collection originale (source), mais avec tri appliqué, filtrage, etc.
, les Références:
- Comment faire: Trier et regrouper les Données en Utilisant une Vue en XAML .
- Wpf's Collection Viewsource .
WPF 4.5 introduit la fonction" Live Shaping "pour CollectionViewSource
.
, les Références:
- WPF 4.5 Nouvelle Fonctionnalité: Live Façonner .
- Collection Viewsource.IsLiveSorting Property .
- repositionnement des données lorsque les valeurs des données changent (mise en forme vivante) .
Solution
S'il y a encore un besoin de trier une instance de la classe ObservableCollection<T>
, voici comment cela peut être fait.
La classe ObservableCollection<T>
lui-même n'a pas de méthode de tri. Mais, la collection pourrait être recréé pour avoir des articles triés:
// Animals property setter must raise "property changed" event to notify binding clients.
// See INotifyPropertyChanged interface for details.
Animals = new ObservableCollection<string>
{
"Cat", "Dog", "Bear", "Lion", "Mouse",
"Horse", "Rat", "Elephant", "Kangaroo",
"Lizard", "Snake", "Frog", "Fish",
"Butterfly", "Human", "Cow", "Bumble Bee"
};
...
Animals = new ObservableCollection<string>(Animals.OrderBy(i => i));
détails supplémentaires
s'il vous Plaît noter que OrderBy()
et OrderByDescending()
méthodes (comme d'autres LINQ–les méthodes d'extension) ne pas modifier la source de la collection! Ils créent plutôt une nouvelle séquence (c'est-à-dire une nouvelle instance de la classe qui implémente IEnumerable<T>
interface). Ainsi, il est nécessaire pour recréer la collection.
je sais est une vieille question, mais est le premier résultat de google pour "sort observablecollection" donc pensé qu'il vaut la peine de laisser mes deux cents.
Le chemin
la façon dont je vais est de construire un List<>
à partir du ObservableCollection<>
, le Trier (par sa méthode Sort()
, plus sur msdn ) et quand le List<>
a été trié, réordonner le ObservableCollection<>
avec le Move()
méthode.
le code
public static void Sort<T>(this ObservableCollection<T> collection, Comparison<T> comparison)
{
var sortableList = new List<T>(collection);
sortableList.Sort(comparison);
for (int i = 0; i < sortableList.Count; i++)
{
collection.Move(collection.IndexOf(sortableList[i]), i);
}
}
Le test
public void TestObservableCollectionSortExtension()
{
var observableCollection = new ObservableCollection<int>();
var maxValue = 10;
// Populate the list in reverse mode [maxValue, maxValue-1, ..., 1, 0]
for (int i = maxValue; i >= 0; i--)
{
observableCollection.Add(i);
}
// Assert the collection is in reverse mode
for (int i = maxValue; i >= 0; i--)
{
Assert.AreEqual(i, observableCollection[maxValue - i]);
}
// Sort the observable collection
observableCollection.Sort((a, b) => { return a.CompareTo(b); });
// Assert element have been sorted
for (int i = 0; i < maxValue; i++)
{
Assert.AreEqual(i, observableCollection[i]);
}
}
j'ai créé une méthode d'extension de la collecte observable
public static void MySort<TSource,TKey>(this ObservableCollection<TSource> observableCollection, Func<TSource, TKey> keySelector)
{
var a = observableCollection.OrderBy(keySelector).ToList();
observableCollection.Clear();
foreach(var b in a)
{
observableCollection.Add(b);
}
}
Il semble que cela fonctionne et que vous n'avez pas besoin de mettre en œuvre IComparable
j'ai regardé ceci, j'étais en train de le trier, et puis il a cassé la reliure, comme ci-dessus. J'ai trouvé cette solution, bien que plus simple que la plupart des vôtres, il semble faire ce que je veux,,
public static ObservableCollection<string> OrderThoseGroups( ObservableCollection<string> orderThoseGroups)
{
ObservableCollection<string> temp;
temp = new ObservableCollection<string>(orderThoseGroups.OrderBy(p => p));
orderThoseGroups.Clear();
foreach (string j in temp) orderThoseGroups.Add(j);
return orderThoseGroups;
}
L'argument OrderByDescending
est une fonction retournant une clé de tri. Dans votre cas, la clé est la chaîne elle-même:
var result = _animals.OrderByDescending(a => a);
si vous voulez Trier par longueur par exemple, vous écrirez:
var result = _animals.OrderByDescending(a => a.Length);
_animals.OrderByDescending(a => a.<what_is_here_?>);
si les animaux seraient une liste D'objet Animal, vous pourriez utiliser une propriété pour commander la liste.
public class Animal
{
public int ID {get; set;}
public string Name {get; set;}
...
}
ObservableCollection<Animal> animals = ...
animals = animals.OrderByDescending(a => a.Name);
il s'agit d'un ObservableCollection<T>
, qui se trie automatiquement sur un changement, déclenche une sorte seulement si nécessaire, et ne déclenche une seule action de changement de collection mouvement.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
namespace ConsoleApp4
{
using static Console;
public class SortableObservableCollection<T> : ObservableCollection<T>
{
public Func<T, object> SortingSelector { get; set; }
public bool Descending { get; set; }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
if (e.Action != NotifyCollectionChangedAction.Reset
&& e.Action != NotifyCollectionChangedAction.Move
&& SortingSelector != null)
{
var query = this
.Select((item, index) => (Item: item, Index: index));
query = Descending
? query.OrderBy(tuple => SortingSelector(tuple.Item))
: query.OrderByDescending(tuple => SortingSelector(tuple.Item));
var map = query.Select((tuple, index) => (OldIndex:tuple.Index, NewIndex:index))
.Where(o => o.OldIndex != o.NewIndex);
using (var enumerator = map.GetEnumerator())
if (enumerator.MoveNext())
Move(enumerator.Current.OldIndex, enumerator.Current.NewIndex);
}
}
}
//USAGE
class Program
{
static void Main(string[] args)
{
var xx = new SortableObservableCollection<int>() { SortingSelector = i => i };
xx.CollectionChanged += (sender, e) =>
WriteLine($"action: {e.Action}, oldIndex:{e.OldStartingIndex},"
+ " newIndex:{e.NewStartingIndex}, newValue: {xx[e.NewStartingIndex]}");
xx.Add(10);
xx.Add(8);
xx.Add(45);
xx.Add(0);
xx.Add(100);
xx.Add(-800);
xx.Add(4857);
xx.Add(-1);
foreach (var item in xx)
Write($"{item}, ");
}
}
}
sortie:
action: Add, oldIndex:-1, newIndex:0, newValue: 10
action: Add, oldIndex:-1, newIndex:1, newValue: 8
action: Move, oldIndex:1, newIndex:0, newValue: 8
action: Add, oldIndex:-1, newIndex:2, newValue: 45
action: Add, oldIndex:-1, newIndex:3, newValue: 0
action: Move, oldIndex:3, newIndex:0, newValue: 0
action: Add, oldIndex:-1, newIndex:4, newValue: 100
action: Add, oldIndex:-1, newIndex:5, newValue: -800
action: Move, oldIndex:5, newIndex:0, newValue: -800
action: Add, oldIndex:-1, newIndex:6, newValue: 4857
action: Add, oldIndex:-1, newIndex:7, newValue: -1
action: Move, oldIndex:7, newIndex:1, newValue: -1
-800, -1, 0, 8, 10, 45, 100, 4857,
myObservableCollection.ToList().Sort((x, y) => x.Property.CompareTo(y.Property));
/// <summary>
/// Sorts the collection.
/// </summary>
/// <typeparam name="T">The type of the elements of the collection.</typeparam>
/// <param name="collection">The collection to sort.</param>
/// <param name="comparison">The comparison used for sorting.</param>
public static void Sort<T>(this ObservableCollection<T> collection, Comparison<T> comparison = null)
{
var sortableList = new List<T>(collection);
if (comparison == null)
sortableList.Sort();
else
sortableList.Sort(comparison);
for (var i = 0; i < sortableList.Count; i++)
{
var oldIndex = collection.IndexOf(sortableList[i]);
var newIndex = i;
if (oldIndex != newIndex)
collection.Move(oldIndex, newIndex);
}
}
Cette solution est basée sur la réponse de Marco . J'ai eu quelques problèmes avec sa solution et l'ai donc améliorée en appelant seulement Move
si l'indice a effectivement changé. Cela devrait améliorer les performances et également résoudre la question liée.