silverlight 4

Dynamic member binding in Silverlight 4

UPDATE: Xavier Decoster already wrote a nice article on this topic some time ago. Please check it out! (Note to self: improve google skills)

First, let me say that I’ll take the long route, so if you are already familiar with dynamic typing in C# you can probably jump straight to the last section. Otherwise read on, you may learn something cool that is not used every day but can save you in some situations.

In the [not so] old days of Silverlight 3 if you wanted to dynamically create a class you had to emit intermediate language instructions, etc. Definitely not so easy. Silverlight 4 (with C# 4.0) introduced support for dynamics and simplified this a lot.

Straight from the DynamicObject documentation, this simple implementation of a dynamic dictionary uses an internal dictionary to store string/object pairs where the key is the member name and value is its associated value.

public class DynamicDictionary : DynamicObject
{
    Dictionary<string, object> dictionary =
        new Dictionary<string, object>();

    public override bool TryGetMember(
        GetMemberBinder binder, out object result)
    {
        return dictionary.TryGetValue(binder.Name, out result);
    }

    public override bool TrySetMember(
        SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;
        return true;
    }
}

In a DynamicObject you have two methods (TryGetMember and TrySetMember) that are invoked every time someone tries to access the objects’ members. In this particular implementation, when this code is executed

dynamic myDynamicObject = new DynamicDictionary();
myDynamicObject.FirstName = "John";
myDynamicObject.Age = 18;

two pairs “FirstName”/”John” and “Age”/18 are stored in the internal dictionary. On the other hand when you do

string test = myDynamicObject.FirstName;

instead of calling the getter of FirstName (like any statically typed object would do), TryGetMember is invoked and the value corresponding to key “FirstName” is looked up from the internal dictionary.

The dynamic keyword tells the compiler that the member will be looked up at runtime, so you can set/get any member you want and the compiler won’t complain: he knows the members will be resolved while the program is running.

The binding problem

Now there is only a small problem with this approach (and it’s the whole point of this post): if you create a binding that targets a dynamic member you’ll get an error. It looks like the Silverlight binding engine “cannot discover” dynamic properties.

For example this does not work:

public dynamic MyDynamicDictionary {  get;     set; }

// ...

MyDynamicDictionary = new DynamicDictionary();
MyDynamicDictionary.Label = "Hello, I'm dynamic!";
 <Button Content="{Binding MyDynamicDictionary.Label}"/> 

brokenBinding

If you look at the output:

System.Windows.Data Error: BindingExpression path error: 'Label' property not found on 'SilverlightApplication22.DynamicDictionary'

Indexed binding to the rescue

Telerik’s Vladimir Enchev explains on his blog how this approach can be used to implement a dataTable-like structure that can back for ex. a datagrid. The clever bit is that he added to the DynamicDictionary the [] indexer:

public object this[string columnName]
{
    get
    {
        if (dictionary.ContainsKey(columnName))
            return dictionary[columnName];
        return null;
    }
    set
    {
        if (!dictionary.ContainsKey(columnName))
        {
            dictionary.Add(columnName, value);
            RaisePropertyChanged(columnName);
        }
        else
        {
            dictionary[columnName] = value;
            RaisePropertyChanged(columnName);
        }
    }
}

Now we have two alternatives to access the dynamically-created members:

// like before:
dynamic myDynamicObject2 = new DynamicDictionary();
myDynamicObject2.FirstName = "John";
myDynamicObject2.LastName = "Smith";

// using []:
var myDynamicObject3 = new DynamicDictionary();
myDynamicObject["FirstName"] = "John";
myDynamicObject["LastName"] = "Smith";

The two approaches have exactly the same effect (notice that in the second version the variable is declared with var instead of dynamic).

Using square brackets to access members has the advantage that you can actually create members using strings: let’s say you have a string/object dictionary, it’s easy to loop the dictionary entries and “create” a member for every key while setting the value as the member value. After this you’ll have an object that mirrors the dictionary:

var source = new Dictionary<string, object>();
source.Add("FirstName", "John");
source.Add("LastName", "Smith");
source.Add("Age", 18);

var target = new DynamicDictionary();
foreach (var entry in source)
    target[entry.Key] = entry.Value;

now target is the same as you would have after doing

new something() { FirstName = "John", LastName = "Smith", Age = 18 };

except that it “adapts” to any key/value you have in the dictionary. Cool eh?!

It turns out that the indexer has another side benefit (that solves the binding problem). In fact Silverlight 4 also introduced indexed bindings: you can create bindings that target indexed structures (like a list or a dictionary) simply using square brackets. The nice thing is that our dynamic class happens to have an indexer.

Let’s revisit our code: if we declare the property as DynamicDictyionary instead of dynamic (we now must set the properties using the indexer because the compiler only allows “non-existing” properties on object of dynamic type):

public DynamicDictionary MyDynamicDictionary { get; set; }

//...

MyDynamicDictionary = new DynamicDictionary();
MyDynamicDictionary["Label"] = "Hello, I'm dynamic!";

and change the XAML to look like this (notice the square brackets)

<Button Content="{Binding MyDynamicDictionary2[Label]}"/>

the dynamic binding does work fine:

okBinding

Happy dynamic binding!

Download the code

Best of Swiss Silverlight 2010

During this year’s Shape 2010 conference in Zurich-Oerlikon, Microsoft Switzerland announced the winners of the Best of Swiss Silverlight 2010 Award in collaboration with the Best of Swiss Web Association, simsa and Netzwoche.

best_of_sw_silver_2010

Incredibly my application Trails of Switzerland won the Bronze award. I was completely taken by surprise (not to mention super excited) because I didn’t really expect anything when I started the project. In fact it was just a “weekend project” to try a couple of things. When I saw the award application form I thought it could be worth a try so I polished a bit the front-end and added a couple of cool gadgets.

I was familiar with the competition’s application procedure also because I already did it a few times before for my company (that won this year’s .NET Award by the way).

boss_bronze_2010

My application leverages Silverlight’s DeepZoom component to show a full topographic map of Switzerland. The base image is a huge 19 Gigapixels (~3 Gigabytes) JPEG, but movement and zooming is wonderfully smooth.

The tricky part was mapping the GPS data to the map and then keeping content synchronized with the DeepZoom zooming and panning.

screenshot-1

Currently Trails of Switzerland is in closed-beta at http://maps.frenk.com and will probably never go live (except if someone wants to buy it from me) for the simple reason that copyrights on the maps are incredibly expensive and I cannot afford to buy them “just for fun”.
To be honest I must say that the Swisstopo maps are of incredible precision and quality, but still are way too expensive for a no-profit application.

The good part is that Trails of Switzerland could probably be ported to Windows Phone 7 (with a major restyling of course) as DeepZoom seems to work very smoothly there too.

I’d like to congratulate the other contest winners (Coresystems AG/Misapor, Extrafilm AG, VASP Datatecture AG/ETHZ, Portia AG/Immostreet AG): your applications were really mind-blowing!

Shape

The conference was very interesting as well. In particular Bob Muglia should have taken notes from Ronnie’s talk on HTML5/Silverlight. If you have watched the PDC2010 keynote (and the twitter/blog-storm that followed) you know what I’m talking about.

As always Laurent’s Bugnion’s talks were interesting, but also many others were worth the trip (in particular from a Windows Phone 7 and design/UX standpoint).

Moral: you never can tell

Moral of the story is you never know where a weekend project is going to bring you. It seems that someone else also agrees on this. This is one of the things I love in this field.

Thanks

Thanks to Microsoft Switzerland and most of all thanks to my wife for the continuous support and for understanding when I forget stuff/don’t listen because I’m thinking about code (i.e. most of the time) :-)

Silverlight 4 is out…

…just a word of caution for developers: if you are still developing with Silverlight 3 and VS2008 don’t install the Silverlight 4 runtime. If you do, you won’t be able to build your SL3 application anymore and you’ll spend the next hour

a) looking for a way to make your app build again

b) looking for the SL3 runtime (that you won’t find anywhere –and won’t correct the situation anyway).

This problem should not arise if you are already on VS2010 because it allows you to choose your target between SL3 and SL4, but if you are stuck with VS2008 you are out of luck.
It seems that the folks at MS think that everybody can just go ahead and migrate all their solutions to VS2010 and SL4 the next day things are released.

Epic fail! Rant over.

P.S. the correct way to make things work again is:

– uninstall the Silverlight 4 runtime (listed as “Silverlight” in the Programs & Features panel)
– restart your machine (no, you cannot skip this step!!!)
– download the Silverlight3 Developer Runtime and install it (hurry up because as soon as they’ll notice they will remove it from the download server!)

And no, you won’t be able to view SL4 websites –but at least your app will build.

UPDATE: forget the rubbish above. If you install the Silverlight 4 developer runtime you will be able to run SL4 apps and build SL3 apps (of course if you had the SL3 SDK). Just don’t install the “normal” SL4 runtime.