There are lots of solutions on the internet attempting to fill this seemingly very-basic omission from WPF. I'm really confused as to what would be the "best" way. For example... I want there to be little up/down arrows in the column header to indicate sort direction. There are apparently like 3 different ways to do this, some using code, some using markup, some using markup-plus-code, and all seeming rather like a hack.
Has anyone run into this problem before, and found a solution they are completely happy with? It seems bizarre that such a basic WinForms piece of functionality is missing from WPF and needs to be hacked in.
It all depends really, if you're using the DataGrid from the WPF Toolkit then there is a built in sort, even a multi-column sort which is very useful. Check more out here:
Vincent Sibals Blog
Alternatively, if you're using a different control that doesn't support sorting, i'd recommend the following methods:
Li Gao's Custom Sorting
Followed by:
Li Gao's Faster Sorting
MSDN has an easy way to perform sorting on columns with up/down glyphs. The example isn't complete, though - they don't explain how to use the data templates for the glyphs. Below is what I got to work with my ListView. This works on .Net 4.
In your ListView, you have to specify an event handler to fire for a click on the GridViewColumnHeader. My ListView looks like this:
In your code behind, set up the code to handle the sorting:
And then in your XAML, you need to add two DataTemplates that you specified in the sorting method:
Using the
DockPanel
withLastChildFill
set to true will keep the glyph on the right of the header and let the label fill the rest of the space. I bound theDockPanel
width to theActualWidth
of theGridViewColumnHeader
because my columns have no width, which lets them autofit to the content. I did setMinWidth
s on the columns, though, so that the glyph doesn't cover up the column title. TheTextBlock Text
is set to an empty binding which displays the column name specified in the header.I use MVVM, so I created some attached properties of my own, using Thomas's as a reference. It does sorting on one column at a time when you click on the header, toggling between Ascending and Descending. It sorts from the very beginning using the first column. And it shows Win7/8 style glyphs.
Normally, all you have to do is set the main property to true (but you have to explicitly declare the GridViewColumnHeaders):
If you want to sort on a different property than the display, than you have to declare that:
Here's the code for the attached properties, I like to be lazy and put them in the provided App.xaml.cs:
I made an adaptation of the Microsoft way, where I override the
ListView
control to make aSortableListView
:The line
((Binding)clickedHeader.Column.DisplayMemberBinding).Path.Path
bit handles the cases where your column names are not the same as their binding paths, which the Microsoft method does not do.I wanted to intercept the
GridViewColumnHeader.Click
event so that I wouldn't have to think about it anymore, but I couldn't find a way to to do. As a result I add the following in XAML for everySortableListView
:And then on any
Window
that contains any number ofSortableListView
s, just add the following code:Where
Controls
is just the XAML ID for the namespace in which you made theSortableListView
control.So, this does prevent code duplication on the sorting side, you just need to remember to handle the event as above.
I wrote a set of attached properties to automatically sort a
GridView
, you can check it out here. It doesn't handle the up/down arrow, but it could easily be added.Solution that summarizes all working parts of existing answers and comments including column header templates:
View:
Code Behinde: