By default, RadGridView will not be able to filter properties which are IEnumerable. However, with two of its features you can easily add this custom functionality. The first feature you need to use are the Custom Filtering Controls which I have explained in one of my earlier blog posts so I will not go into detail here.

The focus of this blog is how to implement the IFilterDescriptor interface so that our data engine can filter your enumerable property. This interface allows you to provide a filtering expression. This expression will be used when the data engine performs the actual filtering. In the sample project that I have attached I have bound the grid to a list of football players. Each player has an IEnumerable<string> property called FormerClubs.

So, if you were to filter the players collection outside RadGridView by using LINQ you would write something like this:

this.players.Where(player => player.FormerClubs.Contains(”Liverpool”));

When you implement the IFilterDescriptor interface you have to return the player.FormerClubs.Contains(”Liverpool”) part from the CreateFilterExpression method. Our data engine will take the expression that you provide, place it in a Where clause and take care of all the rest. Here is my implementation of the IFilterDescriptor interface:

private static readonly MethodInfo EnumerableCastMethod = typeof(Enumerable).GetMethod("Cast");
private static MethodInfo GenericContainsMethod = GetGenericContainsMethodInfo();

private static MethodInfo GetGenericContainsMethodInfo()
{
    // get the Enumerable.Contains<TSource>(IEnumerable<TSource> source, TSource value) method,
    // because it is impossible to get it through Type.GetMethod().
    var methodCall = ((MethodCallExpression)((Expression<Func<IEnumerable<object>, bool>>)(source => source.Contains(null))).Body).Method.GetGenericMethodDefinition();
    return methodCall.MakeGenericMethod(typeof(object));
}

/// <summary>
/// The whole 'magic' happens here. You need a basic knowledge about Linq Expressions
/// in order to be able to follow what is going on here.
/// The result of this method will be transformed into a Lambda and then put inside
/// a Where method call on the source collection.
/// </summary>
public Expression CreateFilterExpression(System.Linq.Expressions.Expression instance)
{
    // FormerClubs
    var propertyName = this.column.DataMemberBinding.Path.Path;

    // player.FormerClubs
    var collectionPropertyAccessor = Expression.Property(instance, propertyName);

    // player.FormerClubs.Cast<object>()
    var genericCollectionPropertyAccessor = Expression.Call(null
        , EnumerableCastMethod.MakeGenericMethod(new[] { typeof(object) })
        , collectionPropertyAccessor);

    // player.FormerClubs.Cast<object>().Contains("the value")
    Expression result = Expression.Call(GenericContainsMethod
        , genericCollectionPropertyAccessor
        , Expression.Constant(this.Value));

    if (this.FilterOperator == FilterOperator.DoesNotContain)
    {
        // !player.FormerClubs.Cast<object>().Contains("the value")
        result = Expression.Not(result);
    }

    return result;
}

You need to have basic understanding of LINQ Expressions in order to follow what I am doing here. I admit that getting the generic Contains method is a bit ugly, but I could not get it with simple reflection.

Here is what I got in the end. Since I am lacking uber-designer skills, I am sure that you can design the UI better than me. The expression stuff was the focus of this blog anyway.

FormerClubs

The fact that the Custom Filtering Controls feature allows you to create any user interface and the IFilterDescriptor interface allows you to create any filtering expression makes the combination of the two extremely powerful. You only need a guy who can draw nice stuff and a guy who can tackle those cryptic LINQ expressions.

Please, find the sample projects attached. There is a Silverlight and WPF version in the attached file.

Happy coding!


About the Author

Rossen Hristov

 is Senior Software Developer in Telerik XAML Team

Comments

Comments are disabled in preview mode.