20

I have an observable collection and I sort it using linq. Everything is great, but the problem I have is how do I sort the actual observable collection? Instead I just end up with some IEnumerable thing and I end up clearing the collection and adding the stuff back in. This can't be good for performance. Does anyone know of a better way to do this?

dove
  • 20,469
  • 14
  • 82
  • 108
Xander
  • 9,069
  • 14
  • 70
  • 129
  • Possible duplicate of [Sort ObservableCollection C#](http://stackoverflow.com/questions/19112922/sort-observablecollectionstring-c-sharp) – Tim Pohlmann Feb 15 '17 at 07:55

6 Answers6

15

If you are using Silverlight 3.0, then using CollectionViewSource is the cleanest way. Refer below example: (it can be done via xaml as well)

ObservableCollection<DateTime> ecAll = new ObservableCollection<DateTime>();
CollectionViewSource sortedcvs = new CollectionViewSource();
sortedcvs.SortDescriptions.Add(new System.ComponentModel.SortDescription("Date", 
    System.ComponentModel.ListSortDirection.Ascending));
sortedcvs.Source = ecAll;
ListBoxContainer.DataContext = sortedcvs;

And in corresponding xaml set

ItemsSource="{Binding}"

for the ListBox or any ItemsControl derived control

moonlightdock
  • 1,358
  • 13
  • 14
9

Since the collection doesn't provide any Sort mechanism, this is probably the most practical option. You could implement a sort manually using Move etc, but it will probably be slower than doing in this way.

    var arr = list.OrderBy(x => x.SomeProp).ToArray();
    list.Clear();
    foreach (var item in arr) {
        list.Add(item);
    }

Additionally, you might consider unbinding any UI elements while sorting (via either approach) you only pay to re-bind once:

Interestingly, if this was BindingList<T>, you could use RaiseListChangedEvents to minimise the number of notifications:

    var arr = list.OrderBy(x => x).ToArray();
    bool oldRaise = list.RaiseListChangedEvents;
    list.RaiseListChangedEvents = false;
    try {
        list.Clear();
        foreach (var item in arr) {
            list.Add(item);
        }
    } finally {
        list.RaiseListChangedEvents = oldRaise;
        if (oldRaise) list.ResetBindings();
    }
Icarus
  • 139
  • 2
  • 13
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • If you're going to go this route, for performance, I'd use `var ordered = list.OrderBy(x => x.SomeProp); list.Clear(); list.AddRange(ordered);` You'll avoid the unnecessary iteration & execution of ToArray() and only do so once during AddRange(). (I'd have to decompile to verify this, since AddRange takes an IEnumerable, it may even just store that without executing it, and then execute & store the flattened collection before any List-specific operations are called. Same performance in the end, but it just defers the cycle hit until later.) – JoeBrockhaus Apr 24 '14 at 16:20
3

Note that in Linq, you are given an IEnumerable from your query, and that query has not executed yet. Therefore, the following code only runs the query once, to add it to an ObservableCollection:

var query = from x in Data
            where x.Tag == "Something"
            select x;

foreach(var item in query)
    MyObservableCollection.Add(item);

Take a look at the "OrderBy" extension on IEnumerable:

foreach(var item in query.OrderBy(x => x.Name))
    MyObservableCollection.Add(item);
Brian Genisio
  • 47,787
  • 16
  • 124
  • 167
  • I used this as a base for something similar for my code. I'm starting to think Linq is pretty kick-ass :) – djcouchycouch Aug 20 '09 at 19:45
  • I am not sure how well this would work if you are getting the ObservableCollection from the WCF service, any advice? Do I need to create a new ObservableCollection on the client and apply "OrderBy" to it? - thanks. – VoodooChild Aug 24 '10 at 02:59
  • @VoodooChild: If you already have an ObservableCollection instead of just an IEnumerable, then look at the SO question: http://stackoverflow.com/questions/996126/sorting-an-observable-collection-with-linq – Brian Genisio Aug 25 '10 at 16:23
3

ObservableCollections aren't designed to be sortable. List is sortable, and that's the underlying mechanism used by the answer referencing List.Sort(), but ObservableCollection isn't derived from List so you're out of luck there. Imo, the "right" solution is not to try to sort the ObservableCollection, but to implement ICollectionView and bind an instance of that to your control. That interface adds methods for sorting and has the additional benefit that its recognized by Silverlight controls (well, the ones that support it anyway such as DataGrid) so your sorting could be utilized directly from the UI layer. This question might be helpful:

Silverlight and icollectionview

Community
  • 1
  • 1
James Cadd
  • 12,136
  • 30
  • 85
  • 134
0

i followed the link mentioned in this post http://mokosh.co.uk/post/2009/08/04/how-to-sort-observablecollection/comment-page-1/#comment-75

but having issues getting it to work in Silverlight

I created a property public SortableObservableCollection Terms When I call Terms.Sort(new TermComparer()) the records are still display unsorted on the UI

could some suggest what could be going wrong. thanks

joblot
  • 383
  • 1
  • 6
  • 18
0

I found this on CodePlex:

Sorted Collections

Haven't used it yet though.

Rick

rboarman
  • 8,248
  • 8
  • 57
  • 87