Home > Development > Filtering and Grouping ListView and GridView on Windows 8

Filtering and Grouping ListView and GridView on Windows 8

One of the questions I recently answered on Stack Overflow was how to filter and group data in ListView and GridView.

Filtering and grouping has traditionally be done with CollectionViewSource. Unfortunately,CollectionViewSource no longer has the Filter event or the GroupDescriptions property. It may seem like filtering and grouping are unsupported, but both can still be achieved using LINQ.

In your Xaml, add a CollectionViewSource in the Resources section of your page. Make sure IsSourceGrouped is set to true:

<common:LayoutAwarePage.Resources>

    <!–
        Collection of grouped items displayed by this page, bound to a subset
        of the complete item list because items in groups cannot be virtualized
    –>
    <CollectionViewSource x:Name="GroupsCV" Source="{Binding Groups}" IsSourceGrouped="True" />
    
</common:LayoutAwarePage.Resources>

 

Now, the CollectionViewSource (GroupsCV) should be set as the ItemsSource for your GridView:

<GridView ItemsSource="{Binding Source={StaticResource GroupsCV}}" />

 

Notice that CollectionViewSource is bound to a property called Groups. This property is part of my ViewModel. The value returned by the Groups property will be the result of a LINQ query. This confused me at first because I didn’t know what type the property should return. I settled on an enumerable grouping of comparable items. This pretty much works with any LINQ query of any type.

So, in your ViewModel (or whatever your DataContext is) add the following property:

private IEnumerable<IGrouping<IComparable, TItem>> groups;
public IEnumerable<IGrouping<IComparable, TItem>> Groups
{
    get { return groups; }
    set { SetProperty(ref groups, value); }
}

 

Now, whenever you want to change the grouping or the filter, just set the Groups property equal to a LINQ query like so:

Groups = from i in musicItems
         group i.Genre into g
         orderby g.Key
         select g;

 

LINQ does great with property expressions in queries at compile time, but what about letting the user pick from a list of property names and dynamically grouping by a property at runtime? Well, the only requirement for LINQ to be able to create a group is that whatever you pass it must implement IComparable.

Here’s a little extension method that takes the name of a property as a string and returns an IComparable:

static public class DataExtensions
{
    static public IComparable GetComparableValue<T>(this T item, string propName) where T : class
    {
        return (IComparable)typeof(T).GetTypeInfo().GetDeclaredProperty(propName).GetValue(item, null);
    }
}

With that in place, you can do a dynamic query by property name like this:

string groupByPropertyName = "Artist";

Groups = from i in musicItems
         group i by i.GetComparableValue(groupByPropertyName) into g
         orderby g.Key
         select g;

 

The examples above show how to create groups, but you can easily filter as well. On the 2nd line of the query (the line after the from) add a where clause. You can filter on any property and should even be able to use the GetComparableValue trick to dynamically filter on a property by quoted string name.

Original Question on Stack Overflow

About these ads
Categories: Development Tags: ,
  1. Robert Stewart
    October 18, 2012 at 1:37 pm

    Jared, I was at one of your presentations in Houston at TechFest. I was looking at doing a cloud based Contact Management system as a Win 8 (WinRT/Win Store) Application. But, from what I have seen, there is no way to connect the application to SQL Server data. Am I worng here? Is there a way that I am not seeing?

  2. October 18, 2012 at 2:22 pm

    Hey Robert. You’re right that Windows Store apps don’t have a SQL driver that can connect directly to SQL Server, but luckily there’s a really awesome alternative that uses SQL server in the back-end. It’s called Windows Azure Mobile Services and you can read about it here:

    https://www.windowsazure.com/en-us/develop/mobile/

    WAMS is INCREDIBLY easy to setup and maintain. It’s dynamic, and it has a very rich client-side library. Soon, it will support other platforms as well.

    I’m currently working on a super-secret project that sits on top of WAMS and ads social shared data capabilities. For a contact management application that may not be of interest, but for scenarios like shared shopping lists or turn-by-turn gaming this will be big. Stay tuned. :)

    Feel free to e-mail me if you have more questions or need help getting your app off the ground!

  3. Marcel
    December 29, 2012 at 11:06 am

    Hi!
    I am really stuck at filtering and sorting my collection! After I found your post, I’ve tried to follow your guide, but it just wont work. Would you please clarify the need of the IEnumerable<IGrouping<IComparable etc? I get the IEnumerable, but what does the IComparable do? (Also, am I missing something about the SetProperty, what should I implement there?)

    Besides that, the advantage of binding directly to an ObservableCollection is that it is Observable. How do you cope with this when binding to the IEnumerable?
    Thanks!

  1. August 1, 2012 at 10:58 pm

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: