Skip Navigation LinksHome > View Post

The Binding you wanted from day one in WPF

Remember when you started playing with WPF? Remember when you coded your first binding?

{Binding ElementName=slider, Path=Value}

and then remember what you wanted to do next? Something like this I'm sure...

{Binding ElementName=slider, Path=Value/2}

(in case you missed it, I'm trying to divide Value by 2). At least I know I've always yearned for basic expression support in WPF bindings. Converters have always allowed you to do this but I've always found the process of creating a converter really interrupts my flow. I've since found ways to partly reduce the friction when using Converters but I'd be happier if I could just have support for expressions.

Long term readers of this blog will remember I'm a big fan of dynamic compilation and, particularly, Expressions which make Dynamic Compilation much easier. And so my idea for a Binding/Converter that supports expressions was born. And here it is:

<Slider x:Name="slider" />
<TextBlock Text="{Binding ElementName=slider, Path=Value, Converter={binding:ExpressionConverter Expression=x/2, InputType=sys:Double, Cache=true}}" />

Or, using the shorter syntax (assuming default values for InputType (double) and Cache (true):

<Slider x:Name="slider" />
<TextBlock Text="{Binding Value, ElementName=slider, Converter={binding:ExpressionConverter x/2}}" />

Nice! How does this work?

Shipping with the Visual Studio 2008 C# samples (available on MSDN Code Gallery) was a rather neat file called Dynamic.cs that contains a neat type called System.Linq.Dynamic.DynamicExpression (not to be confused with the DynamicExpression type that will ship with .NET 4.0).

This supports the parsing of LambdaExpressions as shown below:

ParameterExpression x = System.Linq.Expressions.Expression.Parameter(typeof(double), "x");

var exp = DynamicExpression.ParseLambda(
    new ParameterExpression[] { x },
    null,
    "x/2");

var func = (Func<double,double>)exp.Compile();

Console.WriteLine(func(5));

Saweet. This little program would dump '2.5' to the Console window. Nice (I was about to start writing my own Exprssion parsing algorithm so thanks to my colleagues Zulfiqar Ahmed and James World for introducing me to this little gem).

This is the key piece of magic but you can download the source (below) to get a full view of the current implementation.

More examples

The reason the InputType defaults to double is because I imagine that the vast majority of times you'll want to use this for some basic layout magic (ActualWidth / 2 etc). However, there are many scenarios where you may wish to change the InputType. For example, imagine we have a type called Item with two DateTime properties, CreatedDate and ModifiedDate:

// TODO - for brevity I haven't implemented INotifyPropertyChanged
public class Item
{
    public string Name { get; set; }
    public DateTime CreateDate { get; set; }
    public DateTime ModifiedDate { get; set; }
}

And we might have a list of these items bound to an ItemsSource:

<ListBox ItemsSource="{Binding}" >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" />
                <TextBlock Text="{Binding CreatedDate, StringFormat='Created: {0:yyyy-MM-dd} '}" VerticalAlignment="Bottom" FontSize="10" />
                <TextBlock Text="{Binding ModifiedDate, StringFormat='Modified: {0:yyyy-MM-dd} '}" VerticalAlignment="Bottom" FontSize="10" />
                <TextBlock x:Name="NewText" Text=" NEW!" Foreground="Red" FontWeight="Bold" Visibility="Collapsed" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

And imagine we would like to highlight 'NEW' items, i.e. those where the ModifiedDate is equal to the CreatedDate and were created in the last week. Easy with the ExpressionConverter and a DataTrigger added to our DataTemplate:

<DataTrigger
    Binding="{Binding Converter={binding:ExpressionConverter 'x.CreatedDate == x.ModifiedDate &amp;&amp; Datetime.Now.AddDays(-7) &lt; x.ModifiedDate', InputType={x:Type local:Item}}}"
    Value="True">
    <Setter TargetName="NewText" Property="UIElement.Visibility" Value="Visible" />
</DataTrigger>

Note, that in this case we have to specify the InputType. Also, we had to encode ampersand and less than in XML. So, did it work? Of course:

ListBox with NEW items highlighted

Performance

So, how does this stuff perform?

Well, not bad actually. The compilation of the expression is relatively slow but this only happens once per converter. Of course, experienced WPFers will know this could easily lead to terrible performance as, if within an DataTemplate used by an ItemsControl, the converter might be created hundreds of times, ouch!

This is why the ExpressionConverter has a Cache property which defaults to true. When Caching is on, compiled expressions are cached in a static dictionary and a matching expression (based on the Expression string and InputType) will always reuse this compiled expression. Note, if you have many different expressions. That is, the expressions are being generated at runtime, then you might leak memory and therefore may choose not to use the cache. Set the Cache property to false if you're worried about this - you will then incur a compilation per Converter. The solution here is to put the Converter high in the resource tree so it's only compiled once and used as a resource wherever needed:
    
<Application.Resources>
    <binding:ExpressionConverter x:Key="SinConverter" Expression="Math.Sin(x)" Cache="false"/>
</Application.Resources>

Anyway, time for some rough figures about the speed of the expression itself. Here are the results for a million invocations of a reasonably complex Expression, "Math.Cos(x)/22+1/x":

Performance of ExpressionBinding

The results you're interested in are the direct invoke and wrapped invoke. direct invoke (which took 269ms for a million invocations) is the same 'expression' as a raw function being invoked directly (note it included conversion to a double as required by an IValueConverter which takes an object parameter). The wrapped invoke represents the dynamically compiled expression also including the converstion to a double. This took 371ms for a million invocations. So it's slower, no suprise, but by a factor of about .3 in this test.

I should point out that, in some tests, the dynamic binding exhibited slower invocations of up to 4x but this really isn't the point. In most cases this performance would be more than adequate as the calculation of the expression (and the addition of the dynamic slowness) which totals a miniscule ~0.0004ms, clearly isn't going to be the bottleneck in your application's peformance. However, for performance sensitive scenarios where you might have thousands of ExpressionBindings, within an ItemsControl for example, you may want to skip this and go the old fashioned way and use a normal Binding and custom IValueConverter.

Download

Usual disclaimers apply and as always - your own mileage may vary.

Tags: WPF C#

 
Josh Post By Josh Twist
5:13 AM
07 Jan 2010

» Next Post: Silverlight, MVVM and Validation Part III
« Previous Post: The Future of Programming

Comments are closed for this post.

Posted by Rob @ 07 Jan 2010 9:01 AM
While it seams pretty cool, this sort of practice can lead to maintenance nightmares as you put more and more code into the Xaml. This is a prime example of violation of Separation of Concerns. The scenarios you describe are better solved using a View Model, where the code is easily discoverable, more maintainable, testable and reusable. That's not to say this idea has no value or isn't useful. I just think you should have a pretty good reason to forgo using a VM in favor of this.

Posted by Josh @ 07 Jan 2010 10:11 AM
Hi Rob,

You make a great point here. I'm definitely a big fan of ViewModel and, in hindsight, some of the examples here might go a little to far.

Having said that I also agree that this can still be useful. I talked about how I still see a big place for Converters in a ViewModel world in this post: http://www.thejoyofcode.com/Model_View_ViewModel_and_Animation.aspx

Thanks for commenting and wise words.

Josh

Posted by Josh Smith @ 07 Jan 2010 10:35 AM
I've seen several variations of this idea over the years, and the same discussion always comes up. As Rob pointed out, the separation of concerns can become "unseparated" too easily. I'm all in favor of using this kind of tool for things like layout tweaks, because writing one-off value converters is a pain. But, as you suggested, perhaps the DateTime example goes a little too far.

Nice job, though. Thanks for sharing this.

Posted by Siderite @ 08 Jan 2010 1:54 AM
As mostly an ASP.Net programmer, I have been hit by the Bind/Eval nightmare on web pages. At first it seems like a good idea, then it gets more cumbersome as you want more complexity and then you end up placing all your code in a RowDatabound event anyway.

However, I do agree that I really dislike writing IValueConverters for banal things like not equal, less than, type conversion and so on. After all, one can abuse any tool, no matter how good the creator's intentions. Oppenheimer comes to mind :)

I rest assured that you will not become the destroyer of WPF for providing useful gizmos such as this, though. Good work!

Posted by sacha @ 08 Jan 2010 2:14 AM
I did something simliar with IronPython :

http://www.codeproject.com/KB/WPF/PythonExpressions.aspx

Posted by Josh @ 08 Jan 2010 2:51 AM
Lol! Thanks SideRite.

@Sacha - Nice, I haven't really looked at IronPython seriously yet. You just bumped it up the queue :)

Posted by Laurent Bugnion @ 10 Jan 2010 3:14 AM
A little known article triggered my curiosity about this kind of converters quite some time ago. I wanted to point you to it, because AFAICS he was the first to publish something like this.
http://www.fikrimvar.net/lestirelim/?p=15

Also, Marlon Grech (the guy at the origin of the WPF disciples group) had something similar on his blog about 2 years ago
http://marlongrech.wordpress.com/2008/02/10/embed-code-in-xaml/

IdentityMine (my employer) had a WPF converter using a similar concept, but with JavaScript as the expression language. This was before we got dynamic expressions in .NET (I think they published it around 2007).

I will probably include something like this in the MVVM Light Toolkit, but in the moment I am rather leaning towards the lambda converter one. I like the lambda syntax. Nice to see another implementation though.

Cheers,
Laurent

Posted by Thomas @ 05 Dec 2011 9:01 PM
i am trying to use this in Silverlight, but SL does not support DynamicExpression.ParseLambda() , anyone knowns a workaround ?

© 2005 - 2014 Josh Twist - All Rights Reserved.