Introduction
This article discusses an elegant way of displaying a LINQ Expression Tree in a WPF TreeView. It's a happy marriage between two hip ways of programming: functional LINQ and declarative WPF.
When playing around with LINQ Expressions, it's important to get a good grasp of what's going on. Visualizing the tree is a key tool in that understanding. Visual Studio 2010 has a Debug view (shown on the left) that displays the expression in a meta-language that's didn't quite work for me and hides the treelike structure of the beast. The standard quick-view in the debugger displays every property and subclass, this also distracted me from the essence.
The included code enables the user to navigate the essence of Expression Trees. It zooms in on those nodes in the tree that derive from System.Linq.Expressions.Expression
. I believe it should be simple enough to change the implementation to display the trees in whatever way the user feels useful.
Background
Expression Trees have been a part of .NET since 3.0. They've been getting some attention, but not by far the amount that is just. The SQL people among us are usually quite comfortable writing code that writes code. I use dynamic SQL quite frequently in my SQL code, and am able to do similar things with Expressions. Very powerful stuff.
This same trick of having a program write itself has been available to the Lisp family of programming languages, where you can can treat code as data and alter the program by manipulating that data. This family has not received a lot of love in the world, I believe mainly because of the Polish Notation. This type of Yoda speak, although arguably a less ambiguous notation than the way we were thought in school, just throws people off when first using these languages. Thrown off users do not add to the success of languages.
Now this trick has come to the .NET platform with LINQ Expressions. For brevity, this article only deals with displaying these trees in WPF. If you want to know more about this exciting new technology, I recommend this as a good starting point.
Using the code
Each node in an Expression Tree derives from an Expression. Usually, it has a few properties that contain other Expressions, thus forming a tree. There is no collection of children on each Expression node, so an adapter was written that uses Reflection to project all properties of type Expression
into such a collection. Here's the listing of the ExpressionAdapter
.
public class ExpressionAdapter {
private le.Expression _Expr;
private string _ParentPropertyName;
public ExpressionAdapter(le.Expression Expr, string ParentPropertyName) {
_Expr = Expr;
_ParentPropertyName = ParentPropertyName;
}
public string Text {
get {
return _ParentPropertyName + " = " + (_Expr == null ?
"null" : (_Expr.NodeType.ToString() + " : " + _Expr.ToString()));
}
}
public IEnumerable<expressionadapter> Children {
get {
if (_Expr == null) return null;
else
return from childExpression in _Expr.GetType().GetProperties()
where childExpression.PropertyType == typeof(le.Expression)
select new ExpressionAdapter((le.Expression)
childExpression.GetValue(_Expr, null), childExpression.Name);
}
}
}
This adapter accepts a node of type Expression
in the constructor and then exposes any properties of type Expression
on that node as an IEnumerable
called Chidlren
. The WPF TreeView
can be bound to that collection to fill the tree.
Below is the code that creates a simple expression and binds the tree to it.
Expression<func><int,>> expr = (x, y) =>
x > 10 ?
y > 20 ?
100
: x * (int)Math.Sqrt(x)
: (int)((x + y) * Math.PI);
List<expressionadapter> l = new List<expressionadapter>() {
new ExpressionAdapter(expr, "Expression") };
tvExpression.ItemsSource = l;
And below is the XAML to let the TreeView
bind to the ExpressionAdapter
:
<Window x:Class="ExpressionsWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF Expression Visualizer" Height="350" Width="525"
xmlns:local="clr-namespace:ExpressionsWpf">
<Grid>
<TreeView Name="tvExpression" ItemsSource="={Binding}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="x:Type local:ExprWrapper"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Text}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
Points of Interest
I was pleasantly surprised that an Expression Tree could be displayed like this with so little code. I like the declarative nature of the code where I only have to specify what needs to be done instead of writing loops to actually do it myself. Actually, I like declarative programming so much that when I see old-school messy code, with a lot of assignments and changes to state after the initial assignment, I feel my mind rejecting it. It's so easy to get those things wrong.
The nice part to notice in this code is that all this is done with lazy evaluation. The Children IEnumerable
only gets enumerated when the user opens the node to actually see the children. This behaviour can be seen by putting a breakpoint on Children_get
and then navigating the tree. When the expression becomes big or cyclic (not sure you can do that, I'll try and let you know), this is a very important advantage.
My first attempt was to bind the TreeView
to the Expression
with a IValueConverter
and an Extension Method on Expession
that exposed the children, but I switched to this approach because it looked cleaner and only needed one auxiliary class (one for the IValueConverter
, and a static one for the extension method). In my coding guidelines, less is more.
I am still not completely satisfied with the constructor where I assign the Expression
to a local variable. In functional programming, state should be on the call stack instead of the heap as much as possible. Here, all these ExpressionAdapter
s are the result of a function call to Children_get
so they are on the stack, except for the top node. Also, the whole thing is immutable, so no problems could arise from it. The code works just fine the way it is, no need to get religious about it.
History
- May 24, 2010: Version 1.0.
- May 24, 2010: Version 1.1: Cleaned up formatting.
- Mar 25, 2010: Version 1.2: Replaced the
Children_get
property with a cleaner LINQ query.