Sorting and grouping in the WPF Property Grid
The Windows Forms property grid control has a PropertySort property which determines whether entries are sorted alphabetically, grouped by category, or both. The WPF Property Grid has no equivalent to this. So how does the WPF Property Grid support sorting and grouping?
The WPF Property Grid accesses its rows via the BindingView collection property. This sounds pretty innocent, but where there’s a data-bound collection in WPF, there’s a collection view, and that means that external code can apply whatever sorting, filtering and grouping it requires. This might be limited to alphabetical sorting and category grouping, or it might be something more application-specific.
Here’s how to reproduce the Windows Forms behaviour:
private static void Sort(PropertyGrid grid) { SortDescription alphabetical = new SortDescription("Node.HumanName", ListSortDirection.Ascending); ICollectionView view = CollectionViewSource.GetDefaultView(grid.BindingView); view.SortDescriptions.Add(alphabetical); } private static void Group(PropertyGrid grid) { PropertyGroupDescription byCategory = new PropertyGroupDescription("Node", new NodeToCategoryConverter()); ICollectionView view = CollectionViewSource.GetDefaultView(grid.BindingView); view.GroupDescriptions.Add(byCategory); }
If this is all you want, you don’t need to write the code yourself: the IsToolBarVisible property displays a toolbar which the user can use to sort and group the grid. (If you want to use CategoryAttribute-based grouping, but don’t want to use the standard toolbar, you can still use the NodeToCategoryConverter in your own grouping code; it’s a public part of the WPF Property Grid API.)
If you need customised sorting or grouping, then this code can serve as a starting point. For example, if you’re presenting a dictionary of values (or an object with many properties which don’t have the CategoryAttribute), you could group them by the first letter of the name as follows:
public class FirstLetterConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { Node node = (Node)value; return node.HumanName.Substring(0, 1).ToUpper(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public partial class MyWindow : Window { private static void GroupByFirstLetter(PropertyGrid grid) { SortDescription sorter = new SortDescription("Node.HumanName", ListSortDirection.Ascending); grid.BindingView.DefaultView.SortDescriptions.Add(sorter); PropertyGroupDescription grouper = new PropertyGroupDescription("Node", new FirstLetterConverter()); grid.BindingView.DefaultView.GroupDescriptions.Add(grouper); } }
Here’s the result:
The main thing to notice is that your SortDescriptions and GroupDescriptions will be applied to the elements of the BindingView class, which are of type PropertyGridRow, so you’ll typically refer to the Node property in your sorting and grouping expressions. From here you can look at the name, the value and the underlying property metadata (such as attributes), so you’ve got a great deal of flexibility to sort and group items as your specific application requires.
For example, suppose you’re using the WPF Property Grid to display and edit a set of dates — maybe milestones in a project plan represented as a Dictionary
public partial class Window1 : Window { private void SortAndGroupGridByDate() { ICollectionView view = propertyGrid1.BindingView.DefaultView; PropertyGroupDescription grouper = new PropertyGroupDescription("Node.Value", new DateToMonthConverter()); view.GroupDescriptions.Add(grouper); SortDescription sorter = new SortDescription("Node.Value", ListSortDirection.Ascending); view.SortDescriptions.Add(sorter); } } public class DateToMonthConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is DateTime) { return ((DateTime)value).ToString("MMMM yyyy"); } else { return "Non-Dates"; } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
This gives a result like this:
In summary, although the WPF Property Grid, unlike the Windows Forms equivalent, doesn’t have a sorting and grouping API per se, its use of the WPF collection view idiom gives you a great deal more freedom to present your data organised in a way which is appropriate to your application and your users’ needs.
3 Responses to “Sorting and grouping in the WPF Property Grid”
Leave a Reply
Categories
BrainDump (1)
Community Code (4)
Events (15)
F# (11)
General (50)
Lab Samples (2)
LightSpeed (249)
MegaPack (7)
News (68)
NHibernate Designer (18)
Nightly news (40)
Phone Elements (22)
Products (87)
Projects (5)
Screencast (6)
SharePoint (3)
Silverlight (14)
Silverlight Elements (59)
SimpleDB Management Tools (20)
Visual Studio (9)
VS File Explorer (7)
Web Workbench (20)
WPF (43)
WPF Diagrams (53)
WPF Elements (91)
WPF Property Grid (32)


Tagged as

Posted by Ivan Towlson on 27 January 2008 



this is helpful, Ivan – how do I hook the firstletterconverter and groupfirstletter methods in the xaml? I have the code, but it doesn’t fire…
Oops, sorry, that wasn’t very clear. You would call the GroupByFirstLetter (or equivalent) method from the code-behind, typically in the window constructor. E.g.
public Window1()
{
InitializeComponent();
propertyGrid1.SelectedObject = new Preferences();
GroupByFirstLetter(propertyGrid1);
}
Apologies for the confusion.
[...] in January, I wrote about sorting and grouping in the WPF Property Grid. I described how to sort entries using [...]