BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Windows Presentation Foundation
.NET 4.0+

WPF Data Binding - Collection Views - Filtering Data

The one hundred and fifth part of the Windows Presentation Foundation Fundamentals tutorial expands upon the previous article, which described collection views. This article manipulates collection views using C# code to apply sorting, grouping and filtering of the data.

Collection Views

In the previous article in the WPF tutorial we introduced collection views, defined using pure XAML via the CollectionViewSource proxy class. These permit you to sort lists of items according to the values of their properties. They also allow you to group the items in a collection and display these groups in ItemsControls with group headers.

You can achieve similar results by creating CollectionView objects from code, rather than XAML. Using code in a .NET language, such as C#, is less declarative but opens up new possibilities. For example, you can add filtering to collections by applying a predicate filter. Items that meet the criteria defined in the predicate are displayed, items that do not are excluded from the view.

In this article we'll demonstrate filtering, as well as briefly revisiting sorting and grouping, using collection views created in C#. We'll create a window that lists a series of products and a set of product options. Initially we'll order and group the data. We'll then add filtering so that only options related to the selected product are visible.

To demonstrate, create a new WPF application solution in Visual Studio named, "CollectionViewFilteringDemo".

Data Classes

We'll start by adding the data classes that we need. The first of these will hold the details of a single product. This will include a code, name and product group name.

public class Product
{
    public string Code { get; set; }
    public string Name { get; set; }
    public string Group { get; set; }
}

For product options we'll use the ProductOption class below. This holds the product code of the product to which the option applies, and the name of the option in the Option property.

public class ProductOption
{
    public string ProductCode { get; set; }
    public string Option { get; set; }
}

The third class, ProductData, contains two observable collections. One will hold products and the other options. We'll use an object of this type as the data context for the window.

public class ProductData
{
    public ProductData(IList<Product> products, IList<ProductOption> options)
    {
        Products = new ObservableCollection<Product>(products);
        ProductOptions = new ObservableCollection<ProductOption>(options);
    }
        
    public ObservableCollection<Product> Products { get; private set; }

    public ObservableCollection<ProductOption> ProductOptions { get; private set; }
}

XAML

We can now create the design for the window that will display the two lists. Replace the XAML in the main window with the code below. Initially, the two list boxes are bound directly to the observable collections.

<Window x:Class="CollectionViewFilteringDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="CollectionViewDemo"
        Height="300"
        Width="450">
    <Grid Background="DarkGreen">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <TextBlock FontWeight="Bold" Foreground="White" FontSize="20">Products</TextBlock>
        <ListBox Grid.Row="1" ItemsSource="{Binding Products}" DisplayMemberPath="Name"/>

        <TextBlock Grid.Column="1" FontWeight="Bold" Foreground="White"
                   FontSize="20">Options</TextBlock>
        <ListBox Grid.Column="1" Grid.Row="1" ItemsSource="{Binding ProductOptions}"
                 DisplayMemberPath="Option"/>
    </Grid>
</Window>

To complete the code, modify the constructor for the main window. The code below creates a new ProductData object with a number of products and options, then sets the data context.

public MainWindow()
{
    InitializeComponent();

    DataContext = new ProductData(
        new List<Product>
        {
            new Product { Code="CC", Name="Coupe", Group="Cars"},
            new Product { Code="SC", Name="Saloon", Group="Cars"},
            new Product { Code="SB", Name="Sports Tourer", Group="Bikes"},
            new Product { Code="CB", Name="Cruiser", Group="Bikes"}
        },
        new List<ProductOption>
        {
            new ProductOption { ProductCode="CC", Option="LED Running Light" },
            new ProductOption { ProductCode="CC", Option="Racing Spoiler" },
            new ProductOption { ProductCode="CC", Option="Pearlescent Paint" },
            new ProductOption { ProductCode="SC", Option="Child Seat" },
            new ProductOption { ProductCode="SC", Option="Boot Organiser" },
            new ProductOption { ProductCode="SB", Option="Sports Exhaust" },
            new ProductOption { ProductCode="SB", Option="Panniers" },
            new ProductOption { ProductCode="SB", Option="Heated Grips" },
            new ProductOption { ProductCode="CB", Option="Chrome Highlights" }
        });
}

Run the program to see the results. The window should appear similar to the image below. Note that the data is not sorted, grouped or filtered.

WPF CollectionView Filtering demonstration window

19 October 2014