ObjectListView Update (18.104.22.168): Complex Filter Expressions
Posted on February 26, 2007
Note: You can download the complete implementation here.
A few people have asked for support of more sophisticated expressions in the Filter property. Previously, ObjectListView allowed only a single relational expression of the form propertyNameOp value, such as Name = ‘Smith’. With this update, you can assign arbitrarily complex expressions to Filter. For example: Name = ‘Smith’ AND (Orders > 50 OR City = ‘Portland’).
The format of the Filter expression is similar to that of the comparison expressions that can be assigned to DataColumn.Expression. Each term is a comparison of the form propertyNamerelationalOp value, and terms can be connected with the Boolean operators AND or OR.
The relational operators that may be used include:
== (synonymous with =)
<> (synonymous with !=)
The value to the right of a relational operator must be a literal; it cannot be the name of another property (a property name will just be interpreted as literal text). String values must be quoted with single or double quotes if they contain spaces or relational operators. If a string value contains a single or double quote, quote the value with the other quote character (e.g. “O’Reilly”).
The Boolean operators AND and OR are case-insensitive. NOT is not currently supported. The AND operator takes precedence over the OR operator. For example, Name = ‘Smith’ AND Orders > 50 OR City = ‘Portland’ requires either both the Name and the Orders comparison to succeed, or the City comparison to succeed.
Parentheses can be used to alter the order of precedence, and can be nested.
Changes to any of the referenced property values in any list item will cause re-evaluation of the filter. In the above example, changes to the Name, Orders, and City property values will cause re-evaluation.
This new method has been added to better support the FilterPredicate property. FilterPredicate is used when the filter criteria cannot be easily expressed with the Filter property. To use it, you set the FilterPredicate to a delegate referencing your own function.
Some typical use cases for FilterPredicate include “sub-property” filter criteria, and dynamic criteria. The sub-property case is one in which a list item property is a class that itself has properties, and you want to filter on one of the properties of the property. An example of dynamic criteria is a combobox selection that determines the filter criteria.
The problem is that previously, ObjectListView didn’t know when to re-apply the FilterPredicate. The filter criteria would be applied when the FilterPredicate was set, and when any list item property changed. Both of the above use cases require the criteria to be re-evaluated at times when the list item properties aren’t changing. In neither case does (or can) ObjectListView have enough information to know to update the filter.
The solution is to expose ApplyFilter() to allow the developer to re-apply the filter when needed. Note that currently, any list item property change will cause the filter to be re-applied, so if you’re just filtering on a list item property in your callback method, you don’t need to call ApplyFilter(). Also, you don’t need to call ApplyFilter() when you’re using the Filter property; it is only needed when using FilterPredicate.
The complex filter expression required a “real” parser and expression-tree evaluator, unlike the cheesy but simple parsing I was able to get away with for a single relational expression. Most of this is traditional computer science stuff and probably doesn’t deserve much discussion. The nifty part of it is the how the expression evaluation is exposed to ObjectListView as a simple predicate delegate, in the same way that a user-supplied FilterPredicate is used. If you’re interested, see the FilterNode and FilterEvaluator classes. Let me know if you see any obvious improvements – this isn’t the kind of work I do on a daily basis, so I have no doubt that it could be better.
What’s up next?
I promised Peter an ObjectListView visualizer for Visual Studio, so that’s next on my agenda. Mihail commented about exposing list item properties in a specific order, which led me to some ideas about providing extended list item properties through ObjectListView. This might be interesting when putting a view over some objects that you don’t have source for (or can’t change for some other reason), and you need expression-style derived properties or something more. Anyway, I’ll report back as I work through the details.
Until next time, happy viewing!