J'ai une classe suivante:
[DataContract]
public class Pair<TKey, TValue> : INotifyPropertyChanged, IDisposable
{
public Pair(TKey key, TValue value)
{
Key = key;
Value = value;
}
#region Properties
[DataMember]
public TKey Key
{
get
{ return m_key; }
set
{
m_key = value;
OnPropertyChanged("Key");
}
}
[DataMember]
public TValue Value
{
get { return m_value; }
set
{
m_value = value;
OnPropertyChanged("Value");
}
}
#endregion
#region Fields
private TKey m_key;
private TValue m_value;
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
#region IDisposable Members
public void Dispose()
{ }
#endregion
}
Ce que j'ai mis dans une ObservableCollection:
ObservableCollection<Pair<ushort, string>> my_collection =
new ObservableCollection<Pair<ushort, string>>();
my_collection.Add(new Pair(7, "aaa"));
my_collection.Add(new Pair(3, "xey"));
my_collection.Add(new Pair(6, "fty"));
Q: Comment puis-je le trier par clé?
Réponses:
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 collections plus importantes, faites attention au nombre de notifications de modification de collection.
J'ai mis à jour mon code pour améliorer les performances et gérer les doublons (merci à nawfal pour avoir mis en évidence les mauvaises performances de l'original même si cela a bien fonctionné sur l'exemple de données d'origine). L'observable est partitionné en une moitié triée à gauche et une moitié droite non triée, où chaque fois que l'élément minimum (tel qu'il se trouve dans la liste triée) est déplacé à la fin de la partition triée à partir de l'élément non trié. Pire cas O (n). Essentiellement un tri par sélection (voir ci-dessous pour la sortie).
utilisation: Exemple avec un observateur (utilisé une classe Person pour rester simple)
Détails de la progression du tri montrant comment la collection est pivotée:
La classe Person implémente à la fois IComparable et IEquatable, ce dernier est utilisé pour minimiser les modifications apportées à la collection afin de réduire le nombre de notifications de modification déclenchées
Pour renvoyer un ObservableCollection, appelez .ToObservableCollection sur * sortedOC * en utilisant par exemple [cette implémentation] [1].
**** réponse orig - 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
la source
ObservableCollection
, mais crée à la place une nouvelle collection.BinarySearch
au lieu deIndexOf
.Cette simple extension a parfaitement fonctionné pour moi. Je devais juste m'assurer que
MyObject
c'était le casIComparable
. Lorsque la méthode de tri est appelée sur la collection observable deMyObjects
, laCompareTo
méthode surMyObject
est appelée, qui appelle ma méthode de tri logique. Bien qu'il n'ait pas toutes les cloches et les sifflets du reste des réponses affichées ici, c'est exactement ce dont j'avais besoin.la source
return Utils.LogicalStringCompare(a.Title, b.Title);
place dereturn string.Compare(a.Title, b.Title);
? @NeilWJ'ai trouvé une entrée de blog pertinente qui fournit une meilleure réponse que celles ici:
http://kiwigis.blogspot.com/2010/03/how-to-sort-obversablecollection.html
METTRE À JOUR
L' ObservableSortedList que @romkyns souligne dans les commentaires maintient automatiquement l'ordre de tri.
Notez cependant aussi la remarque
la source
Vous pouvez utiliser cette méthode simple:
Vous pouvez trier comme ceci:
Plus de détails: http://jaider.net/2011-05-04/sort-a-observablecollection/
la source
ObservableCollection
lié à ItemSource des listes déroulantes et vous ne voyez pas du tout la collection. Aussi cette opération de vidange et de remplissage est ultra rapide ... la "lente" peut être celle qui est déjà optimisée. enfin, vous pouvez modifier ce code pour implémenter votre méthode de déplacement, avoir lesortedlist
etsource
le reste est facile.Move
événements, cela aussi uniquement pour les personnes réellement émues.WPF fournit un tri en direct prêt à l' emploi à l'aide de la
ListCollectionView
classe ...Une fois cette initialisation terminée, il n'y a plus rien à faire. L'avantage par rapport à un tri passif est que ListCollectionView fait tout le gros du travail d'une manière transparente pour le développeur. Les nouveaux éléments sont automatiquement placés dans leur ordre de tri correct. Toute classe qui dérive de
IComparer
de T convient à la propriété de tri personnalisée.Consultez ListCollectionView pour la documentation et les autres fonctionnalités.
la source
J'ai aimé l'approche de la méthode d'extension de tri à bulles sur le blog de "Richie" ci-dessus, mais je ne veux pas nécessairement simplement trier en comparant l'objet entier. Je souhaite plus souvent trier sur une propriété spécifique de l'objet. Je l'ai donc modifié pour accepter un sélecteur de clé comme le fait OrderBy afin que vous puissiez choisir sur quelle propriété trier:
Ce que vous appelleriez de la même manière que vous appelleriez OrderBy, sauf qu'il triera l'instance existante de votre ObservableCollection au lieu de renvoyer une nouvelle collection:
la source
OrderBy
, puis de faire une comparaison pour déterminer le changement réel.La réponse de @ NielW est la voie à suivre, pour un véritable tri sur place. Je voulais ajouter une solution légèrement modifiée qui vous permet de contourner l'utilisation
IComparable
:maintenant, vous pouvez l'appeler comme la plupart des méthodes LINQ:
la source
if(!Ascending) sorted.Reverse();
juste avant lefor
: D (et pas besoin de vous soucier de la mémoire, cette méthode Reverse ne crée aucun nouvel objet, elle est inversée en place)Je voudrais ajouter à la réponse de NeilW . Pour incorporer une méthode qui ressemble au orderby. Ajoutez cette méthode en tant qu'extension:
Et utilisez comme:
la source
Une variante est l'endroit où vous triez la collection sur place à l'aide d'un algorithme de tri par sélection . Les éléments sont mis en place à l'aide de la
Move
méthode. Chaque mouvement déclenchera l'CollectionChanged
événement avecNotifyCollectionChangedAction.Move
(et aussiPropertyChanged
avec le nom de la propriétéItem[]
).Cet algorithme a quelques propriétés intéressantes:
CollectionChanged
événements déclenchés) est presque toujours inférieur à celui d'autres algorithmes similaires comme le tri par insertion et le tri par bulles.L'algorithme est assez simple. La collection est itérée pour trouver le plus petit élément qui est ensuite déplacé au début de la collection. Le processus est répété à partir du deuxième élément et ainsi de suite jusqu'à ce que tous les éléments aient été mis en place. L'algorithme n'est pas très efficace, mais pour tout ce que vous allez afficher dans une interface utilisateur, cela ne devrait pas avoir d'importance. Cependant, en termes de nombre d'opérations de déménagement, c'est assez efficace.
Voici une méthode d'extension qui, pour simplifier, nécessite que les éléments implémentent
IComparable<T>
. D'autres options utilisent unIComparer<T>
ou unFunc<T, T, Int32>
.Le tri d'une collection consiste simplement à appeler la méthode d'extension:
la source
T
pour pouvoir trier les éléments de la collection. Le tri implique le concept de plus et moins de et vous seul pouvez définir commentProfileObject
est ordonné. Pour utiliser la méthode d'extension, vous devez implémenterIComparable<ProfileObject>
surProfileObject
. D'autres alternatives sont comme indiqué en spécifiant unIComparer<ProfileObject>
ou unFunc<ProfileObject, ProfileObject, int>
et modifiez le code de tri en conséquence.Pour améliorer un peu la méthode d'extension sur la réponse xr280xr, j'ai ajouté un paramètre booléen facultatif pour déterminer si le tri est descendant ou non. J'ai également inclus la suggestion de Carlos P dans le commentaire de cette réponse. Veuillez voir ci-dessous.
la source
Avez-vous besoin de garder votre collection triée à tout moment? Lorsque vous récupérez les paires, avez-vous besoin qu'elles soient toujours triées, ou ce n'est que pour quelques fois (peut-être juste pour la présentation)? Quelle sera la taille de votre collection? De nombreux facteurs peuvent vous aider à décider de la méthode à utiliser.
Si vous avez besoin que la collection soit triée à tout moment, même lorsque vous insérez ou supprimez des éléments et que la vitesse d'insertion n'est pas un problème, vous devriez peut-être implémenter une sorte de
SortedObservableCollection
@Gerrie Schenck mentionné ou vérifier cette implémentation .Si vous avez besoin que votre collection soit triée quelques fois, utilisez:
Cela prendra du temps pour trier la collection, mais même dans ce cas, cela pourrait être la meilleure solution en fonction de ce que vous en faites.
la source
Ma réponse actuelle est déjà celle qui a le plus de voix, mais j'ai trouvé une manière meilleure et plus moderne de le faire.
la source
Créez une nouvelle classe
SortedObservableCollection
, dérivez-laObservableCollection
et implémentez-laIComparable<Pair<ushort, string>>
.la source
Une façon serait de le convertir en une liste, puis d'appeler Sort (), en fournissant un délégué de comparaison. Quelque chose comme:-
(non testé)
la source
Je pense que c'est la solution la plus élégante:
http://www.xamlplayground.org/post/2009/07/18/Use-CollectionViewSource-effectively-in-MVVM-applications.aspx
la source
Que diable, je vais également ajouter une réponse rapidement bricolée ... cela ressemble un peu à d'autres implémentations ici, mais je l'ajouterai quand même:
(à peine testé, j'espère que je ne me gêne pas)
Décrivons d'abord quelques objectifs (mes hypothèses):
1) Doit trier
ObservableCollection<T>
en place, pour maintenir les notifications, etc.2) Ne doit pas être horriblement inefficace (c'est-à-dire quelque chose de proche de la "bonne" efficacité de tri standard)
la source
Aucune de ces réponses n'a fonctionné dans mon cas. Soit parce qu'il fout la liaison, ou nécessite tellement de codage supplémentaire que c'est une sorte de cauchemar, soit la réponse est tout simplement cassée. Alors, voici une autre réponse plus simple que j'ai pensé. C'est beaucoup moins de code et cela reste la même collection observable avec un type de méthode this.sort supplémentaire. Faites-moi savoir s'il y a une raison pour laquelle je ne devrais pas le faire de cette façon (efficacité, etc.)?
... Où ScoutItem est ma classe publique. Cela semblait juste beaucoup plus simple. Avantage supplémentaire: cela fonctionne réellement et ne gâche pas les liaisons ou ne renvoie pas une nouvelle collection, etc.
la source
D'accord, comme j'avais des problèmes pour faire fonctionner ObservableSortedList avec XAML, j'ai continué et j'ai créé SortingObservableCollection . Il hérite d'ObservableCollection, il fonctionne donc avec XAML et je l'ai testé à une couverture de code de 98%. Je l'ai utilisé dans mes propres applications, mais je ne promets pas qu'il soit sans bogue. N'hésitez pas à contribuer. Voici un exemple d'utilisation de code:
C'est un PCL, il devrait donc fonctionner avec Windows Store, Windows Phone et .NET 4.5.1.
la source
new
toutes ces méthodes, si quelqu'un a une instance de type plus générique, ces méthodes ne seront pas appelées. Au lieu de cela,override
chaque méthode remplaçable et modifiez-les si nécessaire ou utilisez la méthode de secoursbase.Method(...)
. Vous, par exemple, n'avez même pas besoin de vous inquiéter.Add
car cela utilise en interne.InsertItem
, donc si.InsertItem
est remplacé et ajusté,.Add
ne gênera pas l'ordre.C'est ce que je fais avec les extensions OC:
la source
Cela a fonctionné pour moi, je l'ai trouvé il y a longtemps quelque part.
Usage:
la source
J'avais besoin de pouvoir trier par plusieurs choses et non pas une seule. Cette réponse est basée sur certaines des autres réponses, mais elle permet un tri plus complexe.
Lorsque vous l'utilisez, passez une série d'appels OrderBy / ThenBy. Comme ça:
la source
J'ai beaucoup appris des autres solutions, mais j'ai trouvé quelques problèmes. Premièrement, certains dépendent d'IndexOf qui a tendance à être assez lent pour les grandes listes. Deuxièmement, mon ObservableCollection avait des entités EF et l'utilisation de Remove semblait corrompre certaines des propriétés de clé étrangère. Peut-être que je fais quelque chose de mal.
Quoi qu'il en soit, A Move peut être utilisé à la place Supprimer / Insérer, mais cela pose certains problèmes avec le correctif de performances.
Pour résoudre le problème de performances, je crée un dictionnaire avec les valeurs triées IndexOf. Pour maintenir le dictionnaire à jour et conserver les propriétés de l'entité, utilisez un swap implémenté avec deux mouvements au lieu d'un tel qu'implémenté dans d'autres solutions.
Un seul déplacement déplace les index des éléments entre les emplacements, ce qui invaliderait le dictionnaire IndexOf. L'ajout d'un second mouvement pour implémenter un échange restaure les emplacements.
la source
la source