Silverlight JavaScript Value Converter


Value converters allow you to modify the value of the source property of a binding before it is applied to the target. As shown in my previous WPF examples, you would normally write a new class implementing the IValueConverter interface which will do the conversion. For simple transforms such as performing basic arithmetic or formatting a string writing a whole new class can feel like overkill. In WPF a nice way of doing simple transformations on bindings is to use the EvalBinding but unfortunately, there is not a version for Silverlight and due to the lack of Markup Extensions it is difficult to create anything similar.

This became a particular problem in a recent Silverlight project where we were using loose XAML to enable different themes per client for portions of the application and could not know all the possible conversion required in advance. I wanted to be able to use some kind of scripting to express how the binding’s value should be modified and to have this all expressed in XAML. I’ve recently seen a few folks using IronPython scripts inside their .NET applications to enable scripting at runtime and I’ve also used Boo in the past to achieve similar functionality. Both of these options would involve bundling their respective libraries to the client which when we’re writing a consumer facing Silverlight application – the extra weight doesn’t seem very attractive.

Of course why bother including a whole new scripting language in your Silverlight application when you’ve already got one? Silverlight applications are more than likely run from inside a browser which can already run JavaScript. Using this we can create a Value Converter which will use a JavaScript function to perform the transformation in the binding.

<TextBlock>
    <TextBlock.Text>
        <Binding Source="{StaticResource Message}" Converter="{StaticResource ScriptConverter}">
            <Binding.ConverterParameter>
                <sys:String>
                    var t = '';
                    for (var i = 0; i &lt; value.length; i++) {
                        t += value.charAt(value.length - 1 - i);
                    }
                    return t;
                </sys:String>
            </Binding.ConverterParameter>
        </Binding>
    </TextBlock.Text>
</TextBlock>

This example will take convert the bound value, "foobar", and run the javascript specified passing in the value of the Binding as the variable named ‘value’. For readers not familiar with Javascript the example will reverse the text, so that "foobar" becomes "raboof" when displayed in the TextBlock. The syntax is a little strange to look at. Because we’re specifying the script we have to use the full definition of the Binding instead of the common inline attribute syntax. Silverlight does not support CData sections so any invalid characters in XML such as the less than comparison in the for statement has to be escaped.

Calling out to the browser to execute the supplied function is surprisingly easy; we simply create the method and invoke it with the value. The body of the ValueConverter only contains 5 lines of code.

public class ScriptValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Format a JSON definition with the converter body making up the function
        var json = "( { 'convert': function(value) { " + parameter.ToString() + "} } )";
        // Create the javascript object
        var o = (ScriptObject)HtmlPage.Window.Eval(json);
        // Get a reference to the Javascript conversion function
        var convertFunction = (ScriptObject)o.GetProperty("convert");
        // Invoke the function with the value to convert from
        var convertedValue = convertFunction.InvokeSelf(value);

        return convertedValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
} 

ScriptValueConverter

I should point out that I haven’t given much thought to performance or security in this example, before using Javascript for your conversions you should think thoroughly about where the script is coming from and how often it will be updated. There is also no error handling so a badly written conversion function will likely tear down your entire application.

Download a sample project here.

Advertisements

4 thoughts on “Silverlight JavaScript Value Converter

  1. xmlns:sys=”clr-namespace:System.Windows.Media;assembly=System.Windows”

    var t = System.Windows.Media.Colors.Green;
    return t;

    Hi,
    Could you tell me why this fails with following error :
    Failed to create a ‘System.Windows.Media.Color’ from the text ‘var t = System.Windows.Media.Colors.Green; return t;’.

    Thanks

  2. Hmm it seems like your site ate my first comment (it was super long)
    so I guess I’ll just sum it up what I had written and say, I’m thoroughly enjoying your
    blog. I as well am an aspiring blog blogger but I’m still
    new to the whole thing. Do you have any tips for rookie blog writers?
    I’d really appreciate it.

  3. I was curious if you ever considered changing the layout of your blog?
    Its very well written; I love what youve got to
    say. But maybe you could a little more in the way
    of content so people could connect with it better.

    Youve got an awful lot of text for only having one or two images.
    Maybe you could space it out better?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s