WPFix Part 3 (Extension Methods)

One of the new features, a.k.a. syntactic sugars, in C# 3.0 is extension methods. At first, it looks like compiler magic and it is no big deal. But isn’t it the same about class method? When a function argument is hidden, suddenly whole world changes. Clearly, OOP is not just a hidden this pointer, but we can think of extension methods as class methods that will only access the public fields. This may look like a step backwards but we are not living in an ideal world, in fact not even close to ideal. This is more like a side-step that will provide new ways forward. One of these new ways is LINQ, language integrated query. However, it is hard to come up with another as useful as LINQ. Is there a way to utilize extension methods in WPF as we did lambda expressions?

While introducing the lambda converters, I said that implementing IValueConverter or IMultiValueConverter is not a complete waste of time. There were two reasons behind this statement and hence two problems ahead of lambda converter with dreams of being the ultimate binding converter.

Problem 1

One of them was code maintainability in large projects, where a converter can be used more than once. Typing the same expression again and again is not an option.

Solution 1

Idea occurred to me, while reading Kent Bogaart‘s article on WPF converters and Josh Smith‘s article on piping value converters. They have both suggested a way to reuse and combine converters. Then, I had one of those, wait a minute, moments. This is where extension methods kick in. We could write our Convert method in an extension method and use them inside the expressions. Not only, maintaining these converters will be easier, but also they will be combinable by nature.


Again, we had to make a few changes to the Dynamic Expression API. Looking for extension methods will be a last resort in a function call. We have the type of the instance, but unfortunately extension methods won’t show up in the type’s methods. These methods are defined in a seperate static class, but they are instance methods. Is there a contradiction here? No, static keyword’s original meaning is that the following function’s address will be constant. It does not mean that function belongs to a class rather than an instance. Here, static denotes that all elements inside the class will be static methods. Extension method calls does not provide the these extension types, so we have to find out all of the static classes before making a decision.

You can skip this paragraph if you are not interested in the details. If you take a look at these classes by reflection, you will notice that they are nothing but abstract sealed classes. At the first call to our new GetExtensionMethod method, we will query these kind of types and put their suitable public static methods in to a lookup table. These methods must have a return value and at least one parameter. If two extension methods with same name and suitable parameters are ambiguous according to the current implementation. Implementation is not hard but I had to take a look into the standards. Please, feel free to ask for an implementation if you ever need one, or better you could provide your suggestion if you are not lazy as I am right now. Thanks to LINQ, this addition took less than half an hour. I am thinking of a series dedicated to LINQ. Again, I surrounded the necessary changes to dynamic.cs by WPFix regions.

Problem 2

The other one was the ConvertBack method, which had no counter-part in a lambda converter. Now that lambda converters are suitable for multiple uses, the need for a backward conversion is higher.

Solution 2

We will simply provide a second expression as a parameter to our markup extension class, LambdaExtension. I was going to simply use another constructor with two parameters, but I guess things are different now that the VS 2008 is released. We have to use the name/value syntax to support backward conversion.

I’m still not sure about multibinding and backward conversion. I did write the required changes, however I didn’t even test it once. I will if I have such a need. Can you point out such a case?

Conclusion

Although it is not production quality code, you can download WPFix3 Solution (VS 2008) and take a look.Unfortunately I’ve lost these files. You can check out the codeplex project. Don’t you wish your RTM had something hot like this? Now, if only intelli-sense was extensible enough.

With this post, I am putting a break on WPFix series. In the future, I will continue the series, with hopefully something different than binding and converting. Until then, I will continue updating codes according to your feed-backs.

24 thoughts on “WPFix Part 3 (Extension Methods)”

  1. Hi,

    I’m studying your project and it looks great.
    I have one (minor) frustration with it though.
    In “dt=>dt.ToOurFormat().ToUpper()….” I’m frustrated by the ToOurFormat() method.

    I try the following quick fix:
    — new extension method
    public static object ToType(this object value, Type type)
    {
    return TypeDescriptor.GetConverter(type).ConvertFrom(value);
    }
    — new expression
    {fix:Lambda “v=>v.ToType({x:Type s:String}).ToUpper().InsideParenthesis()”}}’

    the expression had a syntax error on ‘{‘ of ‘{x:Type s:String}’

    I guess that can be solved in much the same way you wrote your binding extension. Idea which I will investigate in a couple of minutes.

    but I thought you might like the idea as well and give it a try too! ;-)

  2. After some reflection I’m almost there with something like:

    — Dynamic change —
    if (resolver != null)
    {
    string qn = token.text.Replace(‘_’, ‘:’);
    Type t = resolver.Resolve(qn);
    if (t != null)
    {
    keywords.Add(token.text, t);
    return ParseIdentifier();
    }
    }


    But then I got an error later on this line (1188)
    return Expression.Call(instance, (MethodInfo)method, args);

    Expression of type ‘System.DateTime’ cannot be used for parameter of type ‘System.Object’ of method ‘System.Object ToType(System.Object, System.Type)’

    If you got any clue that would be nice!
    Investigating…

    Also.. That would be a nice idea if the parameter, as defined in the fix:Binding class are just plain object.
    Then, in the add binding method you check wether they are binding or not. if not create a binding with the arg object as the source. that would be more versatile, and I could replace

    {Binding Source={x:Type s:String}}
    with
    {x:Type s:String}

  3. I mean for the XAML

    <TextBlock
    Text='{fix:Binding t={Binding Source={x:Type s:String}},
    v={Binding Source={x:Static s:DateTime.Now}},
    Forward=”local_Converters.ToType(v,t).ToUpper().InsideParenthesis()”}’/>

  4. i.e. suggested AddBinding

    private void AddBinding(string p, object value)
    {
    Binding bind = value as Binding;
    if (bind == null)
    bind = new Binding() { Source = value };
    this.Parameters.Add(p);
    this.MultiBinding.Bindings.Add(bind);
    }

  5. Oops.. sorry for all my last post….
    lambda expression are strongly typed…
    ToType() will return an object and ToUpper() will fail, as it just happens.

    I can’t see a solution to that.. mmh..

  6. Lloyd;

    Surely, my naming is a punishable act; however, it is just a converter method, specific to your application. In this particular case, it returns a message containing the number of days passed since millennium. Point is, it also happens to return a string, so you can combine string extension methods.

    Before any further coding, can you clarify your intentions?

  7. Well I loved the concept of extension method, makes things so neat and tidy.
    And I also love the ability to pass multiple parameters.

    And I was trying to mix them all up and playing / discovering the API.

    In this exited newbie state I spotted the “ToMyFormat()” function and was a bit disappointed.

    That was about my state of mind and goals, now to my findings.

    I now realize strong typing and absence of generic prevent us to make a function kind of ToType(value, type), ha well too bad.

    I also realize that I can use fix:Binding to pass multiple parameters and use extension methods at the same time, sweet (hmm.. I should really test this one, I mean to use the parameter in further extende method down the line)

    I hacked the library so that the parameter in fix:Binding can be values (as in {x:Static …}, {x:Type …}, etc…), sweet!

    I hacked the library so that my fix:Binding parameter can be {x:Type local_MyType}, sweet! (note the XAML namespace qualifier)

  8. Hi. I’m having some trouble with WPFix and null values passed to the lambda parser. It seems it cannot handle null parameters well, and behaves very oddly. First of all I get the typical WPFix exception of ‘ ” is not a declared namespace.’ So I tried to hack it into returning ‘nullLiteral’ in such cases, but that just causes further problems down the road (namely for some reason it thinks the boolean expression should be of the type of the final result).

    Here’s what I’m trying to do:

    “target==active?1.0:0.0″

    …where target and active are both object references. The idea is I have a property Active that is set to the “active” object, but has the ability to be null as well, if there isn’t an active object, and all I’m trying to do is check if target is the active object.

    So, it’s not that I can’t work around this, but the ?: syntax seems to work fine if active isn’t null. It’s just that everything blows up when it’s null.

  9. P.S.
    Perhaps you should start a SourceForge/CodePlex project for WPFix? This would be a great project to get some community involvement for, since it’s such an important (missing) piece of WPF. I would totally get involved in that. Your thoughts?

  10. I didn’t have time to look into code, however I can guess the problem. Writing lambdas in XAML is like:

    var mult = (a,b)=>a*b;

    Isn’t this impossible? Exactly! What we are trying to do is to wait for the first call of mult and fix types of a and b. If mult is called with a null parameter for the first call, we are helpless since null is the same for all the reference types.

    This also shows that if our parameters change type at runtime, we are doomed. If we switch to generating a new expression at each call, we will definitely hit a performance barrier. I have a few ideas to solve these kinds of issues however I am not sure how it compares to writing a standard converter.

    Thanks for bringing this issue up. As you mentioned, WPFix is also hosted at CodePlex. If you definitely need this kind of functionality, please post an issue there and we will see where this takes WPFix to.

  11. Hi. I’ve done a little fiddling and managed to come up with a way for null values to be supported, but it involves explicitly mentioning the types, rather than inferring them at convert time. (I’m currently using ConverterParameter to pass the type to the convert function since it was not being used in your implementation).

    Thus it’s not the most elegant or convenient syntax, but at least it works. I did it in such a way that it’s only required if a value could be null; therefore if the ConverterParameter isn’t provided it defaults to its original behavior.

    Here are the relevant changes:

    public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
    if ( this.ForwardOperation == null ) {
    if ( value == null && parameter == null )
    return Binding.DoNothing;
    ForwardOperation = ConstructOperation( this.Forward, value, parameter as Type, targetType );
    }
    try {
    return this.ForwardOperation.DynamicInvoke( value );
    } catch {
    return Binding.DoNothing;
    }
    }

    private Delegate ConstructOperation( string code, object value, Type valueType, Type targetType ) {
    int opi = code.IndexOf( “=>” );
    if ( opi ” );
    string param = code.Substring( 0, opi );
    string body = code.Substring( opi + 2 );
    ParameterExpression p = Expression.Parameter( valueType != null ? valueType : value.GetType(), param );
    LambdaExpression lambda = DynamicExpression.ParseLambda( this.TypeResolver, new ParameterExpression[] { p }, targetType, body, value );
    return lambda.Compile();
    }

  12. Thanks for the effort. Glad to see people who wants to contribute.
    There are, I believe, similar solutions which might be leaner on the XAML side. I am not very fond of writing actual code as a comment. However, I will update the CodePlex project as soon as I find a couple of hours.

  13. Mysterious problem with LambdaExtension!

    I’m trying to make a UIElement visible depending n some boolean, and it throws some mysterious looking exception. I wonder if you could share some light one the problem?

    Here is the code which I’m attempting to run:

    <Window
    x:Class=”VisiTest.Window1″
    xlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
    xmlns:pix=”clr-namespace:WPFix;assembly=WPFix”
    Title=”Window1″ Height=”300″ Width=”300″>
    <StackPanel Orientation=”Vertical”>
    <CheckBox x:Name=”cVisi” Content=”Button is visible”/>

    <Button Content=”OK”
    Visibility=”{Binding IsChecked, ElementName=cVisi, Converter={pix:Lambda ‘b=>b?Visibility.Visible:Visibility.Collapsed’}}”/>
    </StackPanel>
    </Window>

  14. I waited Microsoft long enough, more than year, -which I can hardly believe-, to offer a standard alternative. I am planning to take some time for a new version.

    @Lloyd
    Please take a look at the comments at part 2.

  15. Ho.. indeed, it’s exactly the same problem as me!

    And.. you said MS is offering a standart alternative?!
    Never heard about it, you got me curious, could you elaborate?

    And you are making a nw version, cool!

    Thanks for your answer!

  16. I’m not sure the overall value of the lambda expressions. Lambda expression written in xmls will be checked and evaluated in runtime, you lose almost all positive effects of type safety.

  17. Hello,

    Nice article! I really like the concept, but I’m running into a problem using this in one particular scenario. When trying to use the is a DataTemplate for a listbox using the following markup

    v.ToString().ToUpper()”}}’/>
    <!—->

    I get the following error:

    Unrecognized property ‘v’ for type ‘WPFix.LambdaExtension’ found while parsing markup extension.

    Any suggestions as to why this doesn’t work when used in a DataTemplate?

  18. Doh- the blog choked on the xaml…
    Perhaps escaping the lt/gts will fix it:

    <ListBox.ItemTemplate>
    <DataTemplate>
    <TextBlock x:Name=’duration’ Text='{Binding Source={x:Static sys:DateTime.Now},
    Converter={fix:Lambda “v=>v.ToString().ToUpper()”}}’/>
    </DataTemplate>
    </ListBox.ItemTemplate>

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">