I’ve been using Silverlight 3 heavily for the past few months, and during that time have discovered many things to love and hate. One problem I faced with Silverlight 3 (that I should have blogged about earlier) is something I think many developers may have faced. In the application I’ve been working on, we’ve broken up our functionality into “partial views” (we’re using MVVM) by encapsulating logic into Silverlight UserControls. Well with this approach, we ran into an interesting binding problem.

Let’s say you have a UserControl, and that UserControl exposes a DependencyProperty. Then within the UserControls content, you try to bind a control to that Dependency Property. Well there’s an interesting issue with that approach in Silverlight 3. Let’s look at a very simple example and see where the problem exhibits itself.

In this example, we’ll be creating a totally useless application to illustrate the point. We’ll have a Page (MainPage.xaml), and one UserControl (MyControl.xaml). The UserControl will consist of a single string property called MyText and the goal is to get that property’s value to be displayed in a TextBlock (which is within the UserControl). We’ll then add that UserControl to the page, and we’ll dynamically set MyText on the UserControl. Simple setup, right? What can go wrong? Well, let’s get started.

The Base Code

As described, the layout for our code is relatively simple. This base-line code will be used for our discussion throughout this post, so lets look at how we would accomplish this with Silverlight. We’ll start with the UserControl (MyControl.xaml). Since we’ll be binding to a Property in the UserControl, we’ll start with the pertinent code for the UserControl (MyControl.xaml.cs). The only code that will be added for the UserControl is a DependencyProperty of MyText.

#region MyText (Dependency Property)
public string MyText
{
    get { return (string)GetValue(MyTextProperty); }
    set { SetValue(MyTextProperty, value); }
}

public static readonly DependencyProperty MyTextProperty =
    DependencyProperty.Register(
    "MyText",
    typeof(string),
    typeof(MyControl),
    new PropertyMetadata(""));
#endregion

Now in the XAML we want to display the value of MyText in a TextBlock. To do this, you can use ElementName binding, which is new in Silverlight 3. If you didn’t guess by the post title, this is where the problem can occur, but let’s code up the UserControl for now and see what happens.

<UserControl x:Class="SL3.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="mycontrol">

    <Grid x:Name="LayoutRoot" Background="Black">
        <TextBlock Text={Binding MyText, ElementName=mycontrol} />
    </Grid>
</UserControl>

I’ve excluded some of the style code for brevity, but that doesn’t affect the example. Fairly straight-forward code, but if you haven’t seen ElementName binding, it may look a bit odd. What’s a bit strange here is binding to the UserControl as the ElementName. Don’t worry, we’ll be talking more about this in a couple of minutes, for now let’s continue working through the base code with the MainPage.xaml.

<UserControl x:Class="SL3.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="clr-namespace:SL3">

    <StackPanel x:Name="LayoutRoot" Background="White">
        <my:MyControl Height="200"
                      MyText="{Binding Text, ElementName=TextPanel}" />
        <TextBox x:Name="TextPanel" />
    </StackPanel>
</UserControl>

We’ll use this sample code to modify the UserControl so we can see what happens. More ElementName binding here, but this is more common. When you type something into the TextBox named TextPanel, it will update the MyText property of my:MyControl, and if MyControl is working correctly, it will display the output in the TextBlock.

That’s all the code. Let’s test it out…  Figure 1 shows the code running…

Figure 01

Figure 1 – Base Code, Everything Works.

The Problem

So with the base-code, let’s make a minor change. Let’s say we need to name our instance of my:MyControl in the MainPage.xaml. In this simple example, we really don’t need it, but with anything a little more complex, you may need to name the control to get access to it through code or binding. Here’s the new content of the MainPage.xaml:

<UserControl x:Class="SL3.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="clr-namespace:SL3">

    <StackPanel x:Name="LayoutRoot" Background="White">
        <my:MyControl x:Name="foobar"
                      Height="200"
                      MyText="{Binding Text, ElementName=TextPanel}" />
        <TextBox x:Name="TextPanel" />
    </StackPanel>
</UserControl>

The only difference here is the addition of x:Name=”foobar” on my:MyControl. Now let’s run the sample again (Figure 2):

Figure 02

Figure 2 – Uh oh! Looks like there’s a problem!

So what happened here? Good question! By assigning an x:Name to our control’s instance, we managed to break the binding back in the MyControl XAML. Looking at the code again, can you guess the problem?

<TextBlock Text=”{Binding MyText, ElementName=mycontrol}” />

The issue is all in the ElementName. Because the UserControl was named myControl and our instance of that control is foobar, Silverlight 3 can’t find the name myControl anymore. Quite annoying. This is one of those problems where it works in places where you don’t name the instances and breaks when you do. Difficult problem to hunt down. By the way, this isn’t an issue in WPF.

What’s the Fix?

In the spirit of Silverlight 4 Beta being released at PDC09, I thought I would try this same problematic code against the Silverlight 4 runtime (Figure 3).

Figure 03

Figure 3 – Hooray, this bug is fixed in Siverlight 4 Beta

Yea! It works.   But of course, we’re using Silverlight 3 today, so what can we do there. Well, there is a fix, but honestly it is somewhat of a hack. Instead of doing the binding using XAML, you need to do it with code, separating the binding from the UI and making it very ugly, especially trying to achieve a XAML only View.   So this fix applies to the UserControl, and our new XAML for MyControl.xaml is as follows:

<UserControl x:Class="SL3.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="mycontrol">

    <Grid x:Name="LayoutRoot" Background="Black">
        <TextBlock x:Name="textBlock1" />
    </Grid>
</UserControl>

That XAML coupled with this code (which I added to the MyControl constructor), fixes the issue:

// This code is a bit of a hack, but works to fix the ElementName binding issue in SL3
Binding textBlockBinding = new Binding("MyText") { Source = this };
textBlock1.SetBinding(TextBlock.TextProperty, textBlockBinding);

Ugly, huh? But now it will work, regardless if your instances are named (Figure 4).

Figure 04

Figure 4 – The “hacky” code works

Conclusion

This is one of those bugs that can drive you nuts. Why would it work sometimes and not the others. So now you know why, and the “fix” for this problem. I’m really looking forward to the fix in Silverlight 4 (as well as the cool new stuff that was announced at #PDC09). With a release cycle like Silverlight’s I guess there won’t be an SP1 to fix this issue, but at least there is a workaround for now. Hope this helps someone, prior to beating their head against a wall like we did when we first encountered the issue.

If you want to play around with the tests I’ve done, I encourage you to download the sample code. I have included both a Silverlight 3 application (with the “binding fix”), and a pure XAML Silverlight 4 project. Note that the Silverlight 4 version needs to be run in Visual Studio 2010 Beta 2, with the Silverlight 4 Beta extensions.

<a href=”https://images.visoftinc.com/2009-11-19/DataBindingProblem.zip target=”_blank”>Download</a>