Introduction

The article discusses a component that enables automated content filtering for the DataGrid (WPF Toolkit DataGrid or System.Windows.Controls.DataGrid). The inspiration was the article "DataGrid with built-in filter functionality" (for Windows Forms) that was also published on CodeProject.

A specific characteristic of this component is that it is not an inherited DataGrid control, but instead a new style is made for the DataGrid's header. That makes future upgrades easier, and increases compatibility with the DataGrid control.

Using this component is extremely simple, you only need to set a new style for the DataGrid header: ColumnHeaderStyle.

With the release of .NET Framework 4.0, DataGrid has become part of the framework, so there is also a Visual Studio 2010 solution without WPFToolkit.dll.

Background

The component uses the LINQ Dynamic Query Library to build up the query string for DataGrid filtering. You should be familiar with the WPF concept of binding, templates, and styles.

Using the Code

Use of the component should be easy. You first have to add a reference to the DataGrid component and for the DataGridFilterLibrary project (or DLL if you wish). For .NET 4.0, add a "PresentationFramework.dll" reference, and for .NET 3.5, add a "WPFToolkit.dll" reference.

Then, in the XAML code where you have the DataGrid, you have to add the xmlns attribute to the root element of the markup file (namespaces wpftoolkit and filter).

Note that for a project that targets .NET 4.0, there is no need to add the WPF Toolkit reference.

Please note that if you want to use shared resources from a Custom Control Library, you must use the ComponentResourceKey markup extension to reference the resource in the DataGridFilterLibrary.

Using DataGridComboBoxColumn

The filter for distinct values (see the EmployeePosition type in the demo project) can be distinct, or the user can enter any text in the TextBox. In the latter case, the search is executed as a text search with the LIKE operator. This behaviour is adjusted using the attached property IsTextFilter.

The filter control for this DataGridComboBoxColumn is going to be a simple TextBox instead of the ComboBox with all-possible values for the employee position (see the column "Position - List Filter" in the demo project).

This is handy when the list has many items, e.g., 100 employee positions.

How Text Search Works

All text searches through the <textbox> are by default case insensitive searches (as the LIKE SQL clause). The filter control also supports wildcard character % operators.

Configuration Options

Configuration is implemented through attached properties. See the following classes: DataGridColumnExtensions, DataGridComboBoxExtensions, and DataGridExtensions.

UserCanEnterText

When applied to the combobox column, the filter combobox is fully editable, i.e., the user can type part of the word and the combobox automatically selects the first appropriate item (like System.Windows.Controls.TextSearch).

Example

Control Commands

IsFilterVisible

It is not really a command, but an attached property. The property controls the visibility of the filter. It can be bound to a toolbar item. For example, see the "Show/Hide Filter (bind to attached property)" toolbar item.

Please note that in the above case, we are binding to the attached properties. Syntax for this is in the form: Path=(namespace prefix:class name.property name, surrounded by parentheses), e.g.:

Path=(filter:DataGridExtensions.ClearFilterCommand)

Notes

The filter library internally uses (also indicated in the code):

Delay Textbox

(My WPF port of the Windows Forms version: http://www.codeproject.com/KB/miscctrl/CustomTextBox.aspx) - for smooth and responsive performance, thus simulating a kind of incremental search. For example, if the user types letters "A-B-C" in intervals less than 250 milliseconds, a search for an ABC text is performed, not 3 searches for A, AB, ABC.

To show the data in the combo box, the previous version used the DataGridComboBoxColumnWithBindingHack class. The solution for the modified combo column can be found here.

Now I am using ObjectDataProvider as a binding source, so the ComboBox.ItemsSource binds to the EmployeePositionList through a StaticResource. For more information, see: WPF DataGrid – Dynamically updating DataGridComboBoxColumn. For this reason, the DataGridComboBoxColumn class is used instead of DataGridComboBoxColumnWithBindingHack.

The example usage (both) is shown in the XAML code of the test project.

Start inserting Employees with new position

When pressed, every second, an employee (also with a new Position, i.e., Position 1, Position 2, Position 3 ...) is inserted in the EmployeeList list. If DataGrid.ItemsSource is an observable collection (source implements INotifyCollectionChanged) and a filter is set, the filter detects a collection change and then re-executes the filtering. Try and set the letter "p" in the filter for the "Position (Text Filter)" column and then press the button.

Thank you for your response.
But it still not working form me.
Now I'im trying to cutumize QueryController.cs.
In createFilterExpressionsAndFilteredCollection method, i added an event handler when my collection properties change.
like this:

I have 2 page which contains only a filter datagrid. I navigate between page with a Frame component (NavigationService.Navigate(targetPage)).

The both of my pages are Stored in Memory (there's no keywords "New" when I Navigate from a page to another). When I switch on a filtergrid page, the App's memory is increased by 5 Mo (with regular Grid there's no increase).

I've retook your test project in order to reproduce the bug without my app context. So I have not find the solution, but I don't understand very well, all the mechanism of the grid. I think you would be more efficient. If you have the time to see the modified test project is here. Just open the task manager, switch many times between "Page 1" and "Page 2" and just observe the RAM increase of the app in your task manager.

Huh, I cannot figure what is causing those errors Try to remove library and then add piece by piece of your code back. From log messages, I can conclude that library is seeking bindings that do not exist. Try to rearrange your Xaml elements in different hierarchy.

I have just one minor problem applying the filter on ICollection-Properties. The itemsource of my datagrid is an IList<MyCustomObject> List. MyCustomObject also has an IList<CustomObjectTwo> IList-property. When it comes to filter the object-path "MyCustomObject.CustomObjectTwo[0].SomeStringProperty" an exception is thrown, because of the ICollection mentioned above. Any ideas to solve this problem?

If I do a filter-request with your library on the bound column mentioned above, the exception
mentioned in my previous post is still throwing and the filter library do not work any longer (an app restart is necessary). Any ideas?

Another problem with DateTime-Fields (dd:MM:yyyy HH:mm:ss): Filtering such column-values do not work for me. On the contrary, filtering column-values without the time part is working as aspected...