Le tri d'un observable et le retour du même objet trié peuvent être effectués à l'aide d'une méthode d'extension. Pour les grandes collections, attention au nombre de notifications de changement de collection.
J'ai mis à jour mon code pour améliorer les performances (grâce à nawfal) et pour gérer les doublons, ce qu'aucune autre réponse ne fait au moment où j'écris ces lignes. L'observable est partitionné en une moitié gauche triée et une moitié droite non triée, où à chaque fois l'élément minimum (tel que trouvé dans la liste triée) est déplacé à la fin de la partition triée à partir de la partition non triée. Dans le pire des cas, O(n). Essentiellement un tri par sélection (voir ci-dessous pour la sortie).
public static void Sort<T>(this ObservableCollection<T> collection)
where T : IComparable<T>, IEquatable<T>
{
List<T> sorted = collection.OrderBy(x => x).ToList();
int ptr = 0;
while (ptr < sorted.Count - 1)
{
if (!collection[ptr].Equals(sorted[ptr]))
{
int idx = search(collection, ptr+1, sorted[ptr]);
collection.Move(idx, ptr);
}
ptr++;
}
}
public static int search<T>(ObservableCollection<T> collection, int startIndex, T other)
{
for (int i = startIndex; i < collection.Count; i++)
{
if (other.Equals(collection[i]))
return i;
}
return -1; // decide how to handle error case
}
l'utilisation : Exemple avec un observateur (utilisation d'une classe Personne pour rester simple)
public class Person:IComparable<Person>,IEquatable<Person>
{
public string Name { get; set; }
public int Age { get; set; }
public int CompareTo(Person other)
{
if (this.Age == other.Age) return 0;
return this.Age.CompareTo(other.Age);
}
public override string ToString()
{
return Name + " aged " + Age;
}
public bool Equals(Person other)
{
if (this.Name.Equals(other.Name) && this.Age.Equals(other.Age)) return true;
return false;
}
}
static void Main(string[] args)
{
Console.WriteLine("adding items...");
var observable = new ObservableCollection<Person>()
{
new Person {Name = "Katy", Age = 51},
new Person {Name = "Jack", Age = 12},
new Person {Name = "Bob", Age = 13},
new Person {Name = "Alice", Age = 39},
new Person {Name = "John", Age = 14},
new Person {Name = "Mary", Age = 41},
new Person {Name = "Jane", Age = 20},
new Person {Name = "Jim", Age = 39},
new Person {Name = "Sue", Age = 5},
new Person {Name = "Kim", Age = 19}
};
//what do observers see?
observable.CollectionChanged += (sender, e) =>
{
Console.WriteLine(
e.OldItems[0] + " move from " + e.OldStartingIndex + " to " + e.NewStartingIndex);
int i = 0;
foreach (var person in sender as ObservableCollection<Person>)
{
if (i == e.NewStartingIndex)
{
Console.Write("(" + (person as Person).Age + "),");
}
else
{
Console.Write((person as Person).Age + ",");
}
i++;
}
Console.WriteLine();
};
Détails de la progression du tri montrant comment la collection est pivotée :
Sue aged 5 move from 8 to 0
(5),51,12,13,39,14,41,20,39,19,
Jack aged 12 move from 2 to 1
5,(12),51,13,39,14,41,20,39,19,
Bob aged 13 move from 3 to 2
5,12,(13),51,39,14,41,20,39,19,
John aged 14 move from 5 to 3
5,12,13,(14),51,39,41,20,39,19,
Kim aged 19 move from 9 to 4
5,12,13,14,(19),51,39,41,20,39,
Jane aged 20 move from 8 to 5
5,12,13,14,19,(20),51,39,41,39,
Alice aged 39 move from 7 to 6
5,12,13,14,19,20,(39),51,41,39,
Jim aged 39 move from 9 to 7
5,12,13,14,19,20,39,(39),51,41,
Mary aged 41 move from 9 to 8
5,12,13,14,19,20,39,39,(41),51,
La classe Personne implémente à la fois IComparable et IEquatable, ce dernier étant utilisé pour minimiser les changements apportés à la collection afin de réduire le nombre de notifications de changement.
- EDIT Trie la même collection sans créer de nouvelle copie *
Pour renvoyer une ObservableCollection, appelez .ToObservableCollection sur *sortedOC* en utilisant par exemple [this implementation][1].
**** orig réponse - cela crée une nouvelle collection **** Vous pouvez utiliser linq comme l'illustre la méthode doSort ci-dessous. Un extrait de code rapide : produit
3:xey 6:fty 7:aaa
Vous pouvez également utiliser une méthode d'extension sur la collection elle-même
var sortedOC = _collection.OrderBy(i => i.Key);
private void doSort()
{
ObservableCollection<Pair<ushort, string>> _collection =
new ObservableCollection<Pair<ushort, string>>();
_collection.Add(new Pair<ushort,string>(7,"aaa"));
_collection.Add(new Pair<ushort, string>(3, "xey"));
_collection.Add(new Pair<ushort, string>(6, "fty"));
var sortedOC = from item in _collection
orderby item.Key
select item;
foreach (var i in sortedOC)
{
Debug.WriteLine(i);
}
}
public class Pair<TKey, TValue>
{
private TKey _key;
public TKey Key
{
get { return _key; }
set { _key = value; }
}
private TValue _value;
public TValue Value
{
get { return _value; }
set { _value = value; }
}
public Pair(TKey key, TValue value)
{
_key = key;
_value = value;
}
public override string ToString()
{
return this.Key + ":" + this.Value;
}
}
0 votes
Cherchez-vous une implémentation de tri dans la classe ou n'importe quel type de tri fera l'affaire ?
0 votes
Je ne suis pas sûr de comprendre cela. En gros, je veux juste que ce soit trié, la collection ne sera pas très grande (20 articles maximum) donc n'importe quoi fera l'affaire (très probablement).
0 votes
Voir ceci pour une solution WPF stackoverflow.com/questions/1945461/
0 votes
Regardez les réponses sur cette page : une indication très claire d'une API défectueuse lorsqu'il faut plus de 22 réponses pour une fonctionnalité critique et de base.
0 votes
Duplicata possible de Trier ObservableCollection<string> en C#