Click here to Skip to main content
13,297,406 members (67,355 online)
Click here to Skip to main content
Add your own
alternative version


62 bookmarked
Posted 29 Jan 2009

Auto-filter for Microsoft WPF DataGrid

, 29 Jan 2009
Rate this:
Please Sign up or sign in to vote.
Allows auto filtering functionality for DataGrid columns.

DataGrid Autofilter


In my last article, I presented a small framework that can be used with the Microsoft Silverlight DataGrid if you want to provide auto-filter support for your grid columns. But, there is one thing left to do, and that is getting the framework ready to work with the WPF DataGrid provided by Microsoft. The source code and binaries for the WPFToolkit library can be found here, you will need it as the projects reference it. Since the changes made for WPF are minor, I am not going to go over it again, so I would ask you to read the previous article to get a view on how everything is designed and it works.

Code Design

Event though the Silverlight article presents all the code design, I will like to focus a little bit on the FilteredCollectionView I have written. This collection class implements ICollectionView and INotifyCollectionChanged, and takes an IList<T> where T is INotifyPropertyChanged. For each item in the list or any added one (in case an ObservableCollection<T> is passed in), it will create a CollectionItem instance which will be stored in an OrderedSet.

private class CollectionItem
    private readonly int _originalIndex;
    private int _orderedIndex = -1;

    public CollectionItem(int originalIndex)
        _originalIndex = originalIndex;

    public int OriginalIndex
        get { return _originalIndex; }

    public int OrderedIndex
        get { return _orderedIndex; }
        set { _orderedIndex = value; }

The first private member is the index to the original collection whereas the second one is the index in the OrderedSet. I will come back to why I am storing these two indexes and why not one is enough.

The OrderedSet is implemented using a red-black tree (I have used the PowerCollections library). Since this article doesn't focus on the data structure, please have a read on the Internet if you are interested in finding out more on what a red-black tree is. In order to place the items in the tree, the set makes use of a comparer, and here is where the first problem might occur if you let the default one used internally by the OrderedSet. Say, T is a IComparable, and you have two different items in the collection that are equal but not reference equal. The set will not allow duplicated items, hence out of the two items, your collection will only have one. That is the reason why I have implemented my own comparer to make use of the item initial source collection index:

private class LocalCollectionComparer<T> : IComparer<CollectionItem>
        where T : INotifyPropertyChanged
    private FilteredCollectionView<T> _filteredCollection;

    internal LocalCollectionComparer(FilteredCollectionView<T> filteredCollection)
        if (filteredCollection == null)
            throw new ArgumentNullException("collection");
        _filteredCollection = filteredCollection;

    #region IComparer<int> Members

    public int Compare(CollectionItem x, CollectionItem y)
        if (x.OrderedIndex != -1 && y.OrderedIndex != -1)
            return x.OrderedIndex.CompareTo(y.OrderedIndex);
        if (!_filteredCollection._isRemoving && _filteredCollection._comparer != null)
            int compare =  _filteredCollection._comparer.Compare(
            if (compare == 0)
                return x.OriginalIndex.CompareTo(y.OriginalIndex);
            return compare;
        return x.OriginalIndex.CompareTo(y.OriginalIndex);


But, using just the initial collection index is not enough when you have a sorting applied. Once you have a sorted description added to the collection view, while removing an item (say, which does not meet the filter criteria), it might not be possible, because of the internal layout of the tree, to find the item as it used the original source collection index for comparison.

As I mentioned about the sort description scenario, I will mention about the comparer used in that case: FilteredSortComparer. Whenever the SortDescription changes and the collection is not empty, a new instance of FilteredSortComparer is created, and the collection view is refreshed to accommodate the changes:

((INotifyCollectionChanged)_sortDescription).CollectionChanged += (sender, e) =>
                            if (_sortDescription.Count > 0)
                                _comparer = new FilteredSortComparer<T>(_sortDescription);
                                _comparer = null;

For every SortDescription available, the comparer will create the IComparer based on the property type involved, and will create an internal class ComparerInfo. Whenever the comparer is invoked, it will iterate the ComparerInfo list, calling each comparer created on the initialization stage:

public int Compare(T x, T y)
    if (x == null)
        if (y == null)
            return 0;
        return -1;
    if (y == null)
        return 1;
    for (int i = 0; i < _comparers.Count; ++i)
        ComparerInfo ci = _comparers[i];
        int comparison = 
             ci.Comparer.Compare(ci.GetValue(x), ci.GetValue(y));
        if (comparison != 0)
            if (!ci.IsAscending)
                comparison = -comparison;
            return comparison;
    return 0;

Using the Code

The first thing you have to do to get this working is defining the ContentTemplate for the DataGridColumnHeader. Within the source code, you can find an example. Here is how the template looks:

<Style TargetType="primitives:DataGridColumnHeader" x:Key="columnHeaderStyle" >
    <Setter Property="Template">
            <ControlTemplate TargetType="{x:Type primitives:DataGridColumnHeader}">
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                        <RowDefinition Height="*"/>

                                 SortDirection="{TemplateBinding SortDirection}"

                                 IsHovered="{TemplateBinding IsMouseOver}"

                                 IsPressed="{TemplateBinding IsPressed}"

                                 IsClickable="{TemplateBinding CanUserSort}"

                                 Background="{TemplateBinding Background}"

                                 BorderBrush="{TemplateBinding BorderBrush}"

                                 BorderThickness="{TemplateBinding BorderThickness}"

                                 Padding ="{TemplateBinding Padding}"

                                 SeparatorVisibility="{TemplateBinding SeparatorVisibility}"

                                 SeparatorBrush="{TemplateBinding SeparatorBrush}"

                        <ContentPresenter Margin="2" 

                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"

                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"

                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
                    <Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" 

                       Style="{StaticResource ColumnHeaderGripperStyle}"/>
                    <Thumb x:Name="PART_RightHeaderGripper" 

                        HorizontalAlignment="Right" Grid.Column="1"

                        Style="{StaticResource ColumnHeaderGripperStyle}"/>
                    <!-- InitalizersManager="{StaticResource filtersViewInitializersManager}" 
                         if you want a different initializers list-->
                    <stepi:DataGridColumnFilter Grid.Row="0" Grid.Column="1"


                                                       Width="Auto" Height="Auto"



                    <Trigger Property="DisplayIndex" Value="0">
                        <Setter Property="Visibility" Value="Collapsed" 


If you want to control the list of IFilterViewInitializers available, you can define a local resource and then bind the InitalizersManager property of the DataGridColumnFilter to it.

<stepi:FilterViewInitializersManager x:Key="filtersViewInitializersManager"/>

The last step is to set up the datagrid column header style to be the one defined above:

<dg:DataGrid  x:Name="dg" ColumnHeaderStyle="{StaticResource columnHeaderStyle}">


  • 27 Jan. 2009 - Version 1.0.0.


This article, along with any associated source code and files, is licensed under The Eclipse Public License 1.0


About the Author

Stefan Bocutiu
Software Developer (Senior) Lab49
United Kingdom United Kingdom
No Biography provided

You may also be interested in...

Comments and Discussions

QuestionHow to make it editable? Pin
langtu448200017-Mar-12 18:57
memberlangtu448200017-Mar-12 18:57 
QuestionI cannot see any filter after I run the application? Pin
Member 432946922-Nov-11 7:25
memberMember 432946922-Nov-11 7:25 
AnswerRe: I cannot see any filter after I run the application? Pin
langtu448200016-Mar-12 0:55
memberlangtu448200016-Mar-12 0:55 
Questioncompatibility issue with last toolkit Pin
pasquale zirpoli20-Oct-11 0:20
memberpasquale zirpoli20-Oct-11 0:20 
QuestionFilter view doesn't work in a XBAP application [modified] Pin
Torruella2-May-11 10:15
memberTorruella2-May-11 10:15 
AnswerRe: Filter view doesn't work in a XBAP application Pin
Paulodevelo6-May-11 0:16
memberPaulodevelo6-May-11 0:16 
QuestionPerformance issue in filtering Pin
chandrashekarkv12-Apr-11 2:31
memberchandrashekarkv12-Apr-11 2:31 
GeneralGrid Template Columns Pin
Shady14u7-Jan-11 15:59
memberShady14u7-Jan-11 15:59 
GeneralOut of range exception Pin
ypozdnyakov12-Dec-10 4:45
memberypozdnyakov12-Dec-10 4:45 
GeneralRe: Out of range exception Pin
baruchl21-Sep-11 15:50
memberbaruchl21-Sep-11 15:50 
GeneralRe: Out of range exception Pin
langtu448200016-Mar-12 0:52
memberlangtu448200016-Mar-12 0:52 
GeneralRe: Out of range exception Pin
baruchl16-Mar-12 6:39
memberbaruchl16-Mar-12 6:39 
GeneralFramework 4.0 Conversion Pin
frontegi19-Oct-10 6:41
memberfrontegi19-Oct-10 6:41 
GeneralRe: Framework 4.0 Conversion Pin
Mert Ozdag25-Oct-10 23:20
memberMert Ozdag25-Oct-10 23:20 
GeneralRe: Framework 4.0 Conversion Pin
langtu448200015-Mar-12 19:28
memberlangtu448200015-Mar-12 19:28 
BugRe: Framework 4.0 Conversion Pin
JakobJonasson19-Jul-12 9:02
memberJakobJonasson19-Jul-12 9:02 
GeneralRe: Framework 4.0 Conversion Pin
silversurger18-Oct-12 2:54
membersilversurger18-Oct-12 2:54 
GeneralRe: Framework 4.0 Conversion Pin
Krunal Parekh25-Dec-13 21:07
memberKrunal Parekh25-Dec-13 21:07 
GeneralRe: Framework 4.0 Conversion Pin
Dermy0813-Oct-15 5:00
memberDermy0813-Oct-15 5:00 
GeneralDoes any one have this in VB Pin
Glen Lewis7-Sep-10 7:16
memberGlen Lewis7-Sep-10 7:16 
GeneralSorting the list of available values Pin
Aaron F Smith6-Aug-10 4:43
memberAaron F Smith6-Aug-10 4:43 
Can the list of available values in the filter list be sorted?
GeneralSetting/Updating the DataContext Pin
grissemann19-Apr-10 0:39
membergrissemann19-Apr-10 0:39 
GeneralRe: Setting/Updating the DataContext Pin
xusan30-Nov-10 14:23
memberxusan30-Nov-10 14:23 
GeneralRe: Setting/Updating the DataContext Pin
xusan30-Nov-10 22:03
memberxusan30-Nov-10 22:03 
GeneralI absolutely cannot get this to work Pin
Joe Sumner16-Mar-10 12:26
memberJoe Sumner16-Mar-10 12:26 
GeneralRe: I absolutely cannot get this to work Pin
swiperthefox18-Mar-10 4:25
memberswiperthefox18-Mar-10 4:25 
GeneralI solved it Pin
rbgkl24-Mar-10 8:30
memberrbgkl24-Mar-10 8:30 
GeneralRe: I solved it Pin
Joe Sumner29-Mar-10 1:43
memberJoe Sumner29-Mar-10 1:43 
QuestionFilter is not getting displayed Pin
Viji Raj4-Mar-10 5:05
memberViji Raj4-Mar-10 5:05 
QuestionExtending the grid for better usability ... Pin
CSharpian20-Jan-10 20:21
memberCSharpian20-Jan-10 20:21 
GeneralAdapting for VS2010 Pin
Member 476961819-Nov-09 9:30
memberMember 476961819-Nov-09 9:30 
GeneralRe: Adapting for VS2010 Pin
wpmccormick20-Nov-09 6:21
memberwpmccormick20-Nov-09 6:21 
QuestionDoesn't work? Pin
Lunchboxtheman27-Oct-09 17:07
memberLunchboxtheman27-Oct-09 17:07 
GeneralFilter option is not showing in column header Pin
Prabu.15-Oct-09 0:03
memberPrabu.15-Oct-09 0:03 
QuestionRe: Filter option is not showing in column header Pin
Viji Raj4-Mar-10 5:08
memberViji Raj4-Mar-10 5:08 
AnswerThis did the trick Pin
Viji Raj20-Oct-10 1:20
memberViji Raj20-Oct-10 1:20 
GeneralAutoFilter in not working Pin
Member 458530124-Aug-09 23:08
memberMember 458530124-Aug-09 23:08 
GeneralRe: AutoFilter in not working Pin
Member 40480207-Sep-11 2:09
memberMember 40480207-Sep-11 2:09 
GeneralFiltering Does'nt work on ComboBox column type Pin
Member 361076725-May-09 22:22
memberMember 361076725-May-09 22:22 
GeneralResultant grid not editable Pin
Member 361076724-May-09 22:00
memberMember 361076724-May-09 22:00 
GeneralFilter and Group Pin
wubly12-May-09 11:04
memberwubly12-May-09 11:04 
GeneralWorking for me only for TextColumns... Pin
Tsury10-May-09 23:50
memberTsury10-May-09 23:50 
GeneralDropDownControl not displaying Pin
spa_war9-May-09 20:29
memberspa_war9-May-09 20:29 
GeneralRe: DropDownControl not displaying Pin
milos.purkert18-Aug-09 5:56
membermilos.purkert18-Aug-09 5:56 
QuestionRe: DropDownControl not displaying Pin
raporter19-Aug-09 0:55
memberraporter19-Aug-09 0:55 
AnswerRe: DropDownControl not displaying Pin
spa_war16-Oct-09 11:44
memberspa_war16-Oct-09 11:44 
Questionscroll bar is not showing into form. [modified] Pin
Asit Kumar Sinha26-Mar-09 22:07
memberAsit Kumar Sinha26-Mar-09 22:07 
QuestionDropDownButton location Pin
groovecontrol12-Feb-09 3:50
membergroovecontrol12-Feb-09 3:50 
AnswerRe: DropDownButton location Pin
Stefan Bocutiu12-Feb-09 14:09
memberStefan Bocutiu12-Feb-09 14:09 
GeneralRe: DropDownButton location Pin
groovecontrol12-Feb-09 19:10
membergroovecontrol12-Feb-09 19:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171207.1 | Last Updated 29 Jan 2009
Article Copyright 2009 by Stefan Bocutiu
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid