Ben
Ben

Reputation: 1032

How to implement multiple levels of sorting on a CollectionViewSource

I originally posted this as a LINQ query - got it working and then realised I had a problem. You can't use LINQ queries to select/filter and order the items in a CollectionViewSource (why oh why didn't I check this first, why oh why isn't this possible?).

So, I am now trying to work out how to sort a filtered CollectionViewSource.

My CollectionViewSource is bound to an ObservableCollection(Of MediaItems). MediaItems contains a child/nested List(Of AdvertOptions).

The parent ObservableCollection(Of MediaItems) - class is structured as follows:

MediaItems
 .ID (int)
 .Src (string)
 .Advert (bool)
 .AdOptions As List(Of AdvertOptions)
 .Counter (int)

AdvertOptions class consists of:
 .Age (int)
 .Gender (int)
 .Priority (int)

I am filtering out any MediaItems that don't meet the following criteria:

MediaItems.Advert = true
AdOptions.Age = x (parameter within triggered function called to perform the filter/sort)
AdOptions.Gender = y (parameter within triggered function called to perform the filter/sort)

After the CollectionViewSource has been filtered, I need to sort the items based on two sort orders so the resulting CollectionViewSource items can be navigated through in my applicaiton using the CollectionViewSource navigation methods (MoveCurrentToX etc).

The sort order I need to apply is:

  1. AdOptions.Priority (in descending order)
  2. By Counter (in ascending order)

The way I am filtering is by using these functions:

Public Shared Sub FilterByAdvertisement(ByVal Item As Object, ByVal e As FilterEventArgs)

    Dim MediaObjectItem As MediaObject = TryCast(e.Item, MediaObject)

    If Not MediaObjectItem.IsAdvertisingMedia = True Then

        e.Accepted = False

    End If

End Sub

Public Shared Sub FilterByAvertisementOption(ByVal Item As Object, ByVal e As FilterEventArgs)

    Dim MediaObjectItem As MediaObject = TryCast(e.Item, MediaObject)

    Dim Items = From m In MediaObjectItem.AdOptions Select m Where m.Age = Current.Age And m.Gender = Current.Gender
    If Items.Count = 0 Then

        e.Accepted = False

    End If

End Sub

Just for reference, I am adding the filter as follows:

Public AdvertisingDataView As CollectionViewSource

AddHandler AppLocal.AdvertisingDataView.Filter, AddressOf FilterByAdvertisement
AddHandler AppLocal.AdvertisingDataView.Filter, AddressOf FilterByAdvertisementOption

I now need to work out how to sort the filtered items. The problem is, CollectionViewSource seems to have limited support for sorting. I can easily sort the Counter using:

AdvertisingDataView.SortDescriptions.Add(New SortDescription("Counter", ListSortDirection.Ascending))

But that's my secondary sort - I want to Sort first by AdOptions.Priority (requires sub-selecting the right item), then by Counter.

I was wondering if creating Groups would help but can't work out if this will provide the sorting capability I'm looking for.

I have looked at the possibility of converting to a ListCollectionView instead of CollectionViewSource, then using a CustomSort but I can't work out how I could implement this and if it would also offer the capability I'm looking for given my primary sort is a value within a nested list.

Can anyone contribute to help me achieve my outcome?

Ben

Upvotes: 1

Views: 2878

Answers (2)

BAndrei
BAndrei

Reputation: 249

I don't know how to write it in VB, but i can show you in c# how it's made:

YourListView = CollectionViewSource.GetDefaultView(tempListView
.OrderBy(x => x.FirstSorting)
.ThenBy(y => y.SecondSorting));

Look how to do the same in VB, and you will fix this.

You have a link right here - http://linqsamples.com/linq-to-objects/ordering/ThenBy-lambda-csharp

Good luck!

Upvotes: 0

Rohit Vats
Rohit Vats

Reputation: 81243

You can achieve multiple levels of sorting on the default view of your CollectionViewSource. There are essentially 3 types of views automatically generated by WPF, all deriving from the CollectionView base class:

  • ListCollectionView -> Created when the collection implements IList.
  • BindingListCollectionView -> Created when the collection implements IBindingList.
  • EnumerableCollectionView -> Created when the collection implements nothing but IEnumerable.

You can always add to multiple SortDescriptor to the SortCollection of your default view like this -

ListCollectionView lcv =
(ListCollectionView)CollectionViewSource.GetDefaultView(myCollection);
lcv.SortDescriptions.Add(new SortDescription(…));

Refer to these links for further refernce -

Upvotes: 2

Related Questions