Click here to Skip to main content
13,344,508 members (58,285 online)
Click here to Skip to main content
Add your own
alternative version


170 bookmarked
Posted 28 Jan 2010

WPF ListView which can do - Sorting, Filtering, Totals, Cell-focus, Editing, and More

, 21 Apr 2010
Rate this:
Please Sign up or sign in to vote.
Enhanced WPF ListView that is almost a DataGrid


It was one of those days. In a solution, the bottleneck was figured out. Once again, it was the third party DataGrid I used. After having tried three different vendors, I was frustrated, and went back to the WPF ListView, and the performance was better again. I wanted the DataGrid to present the data fast, specially when I reset the ItemsSource to a new collection.

Without a doubt, the commercial DataGrids are nice looking and feature rich. But the overhead on all that slows them down. The DataGrid from Microsoft never could win my interest, it seems somewhere in between the ListView and the commercial DataGrids. Anyways, I started to tweak the ListView, and here is what I've managed to do.

The Basic Usage Should be Easier

Some thing always annoyed me when using commercial DataGrids or the ListView itself. I was tired of writing all those CellTemplates I would have to use. WPF has its own paradigm, but a DataGrid is a DataGrid, at least most of the time.

Wanted Features

  • Common configuration scenarios available through properties
  • Default style for the whole grid and optional styles for columns
  • Lightweight styling and customizing without re-templating
  • Sorting any column, and SortName property for first-run
  • Filtering any column (AutoFilter row)
  • Totals/Summaries for any column
  • Frozen column left/right
  • GridLines vertical and horizontal
  • Cell-focus (cursor)
  • Cell-editing

Using the Code

The basic usage of the DsxDataGrid is pretty straightforward. You can think of it as a 'ListView'. It is a custom control derived from Selector. The ControlTemplates are mainly based on the ListView. The following snippet shows most of the properties for the additional features:

<dsx:DsxDataGrid x:Name="dataGrid1"




















      <dsx:DsxColumn FieldName="MarkFlag" ColumnArea="Left" 

                     Header="" Width="25" 

                     IsSizable="False" IsSortable="False"

                     ViewType="CheckBox" FilterType="CheckBox" 

                     FooterType="None" EditType="None"

      <dsx:DsxColumn FieldName="CompanyName" ColumnArea="Left" 

                     Header="Company" Width="120" 

                     IsSizable="False" ViewType="Text" 

                     FilterType="TextBox" FooterType="Count" 

                     EditType="TextBox" CellHAlign="Left"


      <dsx:DsxColumn FieldName="ContactTitle" ColumnArea="Center" 

                     Header="Title" Width="120" 

                     ViewType="Text" FilterType="ComboBox" 

                     FooterType="None" EditType="ComboBox"


                     CellContentItemsSource="{x:Static local:ContactTitles.ComboSource}"/>

Most basic columns are ready to use without CellTemplates. Behind the scenes, the CellTemplates are generated.

The Basic Layout of DsxDataGrid


The DataGrid is divided in three areas. Each area contains a ListView with the same style. The right area is configured to show the vertical scrollbar, and contains the additional areas that fill the special rows. The header (blue), filter (green), and footer (purple) are all GridViewHeaderRowPresenters but with different Styles (ControlTemplates). The synchronization of the vertical scrolling is done by the very useful ScrollSynchronizer: Scroll Synchronization by Karin Huber

Important: If the left and center areas are not needed, only the area on the right is shown.

Column ViewTypes

Each column has a ViewType (default is Text). This injects a CellTemplate to be created that does everything needed.

public enum EViewType
    Text        = 1,
    Integer     = 2,
    Decimal     = 3,
    Currency    = 4,
    Date        = 5,
    Boolean     = 6,  // displays BulletChrome
    CheckBox    = 7,
    Image       = 8,
    Progress    = 9,

In order to serve the different ListView areas, the columns are recreated inside the contained ListView Columns collections. In this step, the column is examined, and depending on the settings, the CellTemplates are generated for the different ViewTypes. In this scenario, I prefer code over XAML, because in code, you can do nasty things like reuse the existing DisplayMemberBinding, and you have full control to minimize the CellTemplates to a minimum.

Column FilterTypes / EditTypes

Each column can have a FilterType and or an EditType, both of type EEditType. If a FilterType is set, the FilterRow displays the FilterCell. The editing is done by placing an Adorner over the current cell. All controls used in the Adorner are configured to look nice even if the cell is of variable height. This approach is much lighter than placing full controls inside column-cells.

public enum EEditType
    None         = 0,
    TextBox      = 1,
    CheckBox     = 2,
    DatePicker   = 3,
    ComboBox     = 4,
    Slider       = 5,
    CellTemplate = 6,  // not valid for Filter

Note: All EditTypes are templated to look nice if the ItemHeight is larger than the EditControl usually is:


Column FooterTypes

A FooterType can be set on a column to display a result on the displayed data. If the displayed data is filtered, the result is narrowed to the filtered data.

public enum EFooterType
    None        = 0,
    Sum         = 1,
    Avg         = 2,
    Min         = 3,
    Max         = 4,
    Count       = 5,

How Sorting/Filtering/Summarize Work

Sorting can be invoked either by setting the SortField property on the DataGrid, or by clicking the column-header. Both check first if the referring column allows sorting. The sorting triggers the DisplaySource (result of displayed data) to be re-evaluated. In there, the ICollectionView will do the sorting.

Filtering is invoked by the Adorner and is not accessible by property. The filtering acts on PropertyChanged, but has a short timer to wait for some time before invoking the routine. The filtering triggers the DisplaySource to be re-evaluated too. A callback handles all filter-columns to be checked.

Summarizing the totals is (like you might guess) also done while rebuilding the DisplaySource. Since there is no way to build a sum without enumerating all relevant items at least once, this is done by a simple loop before presenting the data.

Custom CellTemplates

In the sample, the column 'Address' uses a custom CellTemplate, triggering the EditMode property that takes control over the editing (entering/exiting). It would probably easier to enhance the existing types in code, so one could as well use a CellTemplate.

How to Define Alternating RowColors

AlternationCount/-Index is already prepared in the ItemsControl. DsxDataGrid just has the collection for the brushes all ready for use, so you just do this, and it will work:

   <SolidColorBrush Color="Yellow"/>
   <SolidColorBrush Color="Red"/>
   <SolidColorBrush Color="OliveDrab"/>

How to Use Styles with DsxDataGrid

My approach is to have a default style for header/filter/footer on the DataGrid that is used for every column, but some columns override the style. The GridViewHeaderRowPresenter gets the style from the custom Control-Template, which refers (if not replaced) to, e.g., the dsxFilterStyle (for FilterRow). In this style, you can see this:

<Style x:Key="dsxFilterStyle" TargetType="{x:Type GridViewColumnHeader}">
    <Setter Property="SnapsToDevicePixels"  Value="true"/>
    <Setter Property="Background"  

       Value="{Binding RelativeSource={RelativeSource Self},
               Converter={StaticResource dsxFilterStyleConverter}, 
    <Setter Property="BorderBrush" 

       Value="{Binding RelativeSource={RelativeSource Self}, 
               Converter={StaticResource dsxFilterStyleConverter}, 
    <Setter Property="Foreground"

       Value="{Binding RelativeSource={RelativeSource Self}, 
               Converter={StaticResource dsxFilterStyleConverter},
    <Setter Property="BorderThickness" 

       Value="{Binding RelativeSource={RelativeSource Self}, 
               Converter={StaticResource dsxFilterStyleConverter},
    <Setter Property="Padding" 

       Value="{Binding RelativeSource={RelativeSource Self},
               Converter={StaticResource dsxFilterStyleConverter}, 
    <Setter Property="Margin" 

       Value="{Binding RelativeSource={RelativeSource Self}, 
               Converter={StaticResource dsxFilterStyleConverter},
    <Setter Property="Template"

       Value="{StaticResource dsxFilterStyleControlTemplate}"/>

All used properties to style the filters refer to a converter. The converter itself evaluates if there is a style on the column overriding the style on the DataGrid, or maybe none at all.

More Details, Sorry So Much!

Unfortunately, I cannot explain all the little tweaks I built in, there are many, and my time is not sufficient for that. Some solutions maybe no rocket science, but they do the job. And yes, I suppose some could be done much more elegantly. But for now, I hope there is some usage for those who come along here because they need ideas.


DsxDataGrid must use ItemFixHeight if IsVirtualizing is set or there are multiple areas (frozen column on left and/or right side).

The filters do not listen to changes in the filtered fields of the underlying source.

What is Missing/Needs Redesign?

  • Grouping, best if IsVirtualizing could be kept (flattened GroupCollections)
  • Make the filter listen to changes
  • Redesign frozen columns (WPFToolKit DataGrid has an implementation)

What I Have Learned?

Having different areas or frozen columns organized in different independent ListViews is not the best practice. I rarely use that so I can go with the current solution for now. If I knew from the start, I would have invested my time in writing my own GridViewRowPresenter. But I did not want to go down that deep when I started. Well, like the saying: all people are smart - some before, some after.


  • 28-Jan-2010 - Initial version
  • 17-Apr-2010 - Updated .NET 4 RTM (StaticResource order problem)
  • 20-Apr-2010 - Updated both source and sample code


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

christoph brändle
Software Developer
Switzerland Switzerland
No Biography provided

You may also be interested in...


Comments and Discussions

GeneralRe: How to get the data row data from dsx grid when check box selected Pin
christoph brändle16-Dec-12 13:19
memberchristoph brändle16-Dec-12 13:19 
Questionhow to get user checked checkBox row Pin
Mogya7-Dec-12 0:40
memberMogya7-Dec-12 0:40 
AnswerRe: how to get user checked checkBox row Pin
christoph brändle7-Dec-12 2:39
memberchristoph brändle7-Dec-12 2:39 
GeneralMy vote of 3 Pin
sangar202019-Nov-12 23:25
membersangar202019-Nov-12 23:25 
Questionhow to set Autogenerate column property Pin
sangar202019-Nov-12 2:06
membersangar202019-Nov-12 2:06 
AnswerRe: how to set Autogenerate column property Pin
christoph brändle20-Nov-12 0:12
memberchristoph brändle20-Nov-12 0:12 
QuestionFilter Pin
PatricN24-Sep-12 23:22
memberPatricN24-Sep-12 23:22 
AnswerRe: Filter Pin
christoph braendle30-Sep-12 12:19
memberchristoph braendle30-Sep-12 12:19 
if you look through the comments to this article you'll find the answer to it

it should get you running Smile | :)
Questionareas? Pin
amirmn715-Sep-12 22:45
memberamirmn715-Sep-12 22:45 
AnswerRe: areas? Pin
christoph braendle17-Sep-12 22:02
memberchristoph braendle17-Sep-12 22:02 
QuestionRe: areas? Pin
amirmn718-Sep-12 19:37
memberamirmn718-Sep-12 19:37 
AnswerRe: areas? Pin
christoph braendle19-Sep-12 11:43
memberchristoph braendle19-Sep-12 11:43 
GeneralRe: areas? Pin
amirmn719-Sep-12 12:28
memberamirmn719-Sep-12 12:28 
GeneralRe: areas? Pin
christoph braendle20-Sep-12 5:50
memberchristoph braendle20-Sep-12 5:50 
QuestionPlease suggest me the control Pin
Member 83712471-Feb-12 1:19
memberMember 83712471-Feb-12 1:19 
AnswerRe: Please suggest me the control Pin
christoph braendle4-Feb-12 2:09
memberchristoph braendle4-Feb-12 2:09 
QuestionHow to get the cell content Pin
Member 83712471-Feb-12 1:16
memberMember 83712471-Feb-12 1:16 
AnswerRe: How to get the cell content Pin
christoph braendle4-Feb-12 2:12
memberchristoph braendle4-Feb-12 2:12 
QuestionThis article is useful! Pin
JunqiSun24-Jul-11 15:58
memberJunqiSun24-Jul-11 15:58 
GeneralMy vote of 5 Pin
KPetrosyan28-Apr-11 6:35
memberKPetrosyan28-Apr-11 6:35 
GeneralDatagrid sorting after importing Excel sheet Pin
mkalantri18-Apr-11 11:42
membermkalantri18-Apr-11 11:42 
QuestionGive and take :) Pin
Scrat987623-Jan-11 12:17
memberScrat987623-Jan-11 12:17 
AnswerRe: Give and take :) Pin
christoph braendle23-Jan-11 22:59
memberchristoph braendle23-Jan-11 22:59 
GeneralRe: Give and take :) Pin
Scrat987625-Jan-11 11:26
memberScrat987625-Jan-11 11:26 
GeneralRe: Give and take :) Pin
christoph braendle26-Jan-11 0:09
memberchristoph braendle26-Jan-11 0:09 

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
Web03 | 2.8.180111.1 | Last Updated 21 Apr 2010
Article Copyright 2010 by christoph brändle
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid