Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data binding the Text property of a Run

I'm trying to databind a Run of a TextBlock in code at runtime, and I can't for the life of me figure out how.

Several sources on the internet suggest this isn't possible without some (not too pretty) additional workarounds, and, more importantly, it should completely fail when you try to do it in XAML.

Yet, in my application I have the following, which works beautifully:

<DataTemplate x:Key="PitchTemplate">
    <Grid Width="120" Height="120" HorizontalAlignment="Center" VerticalAlignment="Center">
        <TextBlock HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   TextAlignment="Center">
            <Run Text="{Binding}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="36"/>
            <LineBreak/>
            <Run Text="{Binding Frequency, StringFormat=\{0:n2\}Hz}" FontFamily="{StaticResource PhoneFontFamilyNormal}" Foreground="{StaticResource PhoneSubtleBrush}"/>
        </TextBlock>
    </Grid>
</DataTemplate>

So I figured: If it can be done in XAML, it should be possible to do it in code.

Sofar, to no avail. Using the "regular" way of binding in code won't work; the Run class doesn't inherit from FrameworkElement, so doesn't have a SetBinding method, and it's Text property is not a DependencyProperty.

Using BindingOperations.SetBinding doesn't work because the Text property is not a DependencyProperty.

I'm up to the point that I'm willing to accept that it can't be done at runtime (although not without a last attempt at StackOverflow), but I'm still curious if

  • This can be done in code at runtime?

And if not:

  • How come it does work in XAML?

EDIT:

The example shown is just there to show that it can be done in XAML. The reason I need to create the bindings in code, is that I have a control that dynamically creates other elements, which need to be data bound.

UPDATE:

As Pete and I both found out, there is a dependency property for Text, but it's private. I assume that's why it does work through XAML (the xaml parser probably has more rights when it comes to reflection, and more knowledge in general about classes).

The upside is, that this means (tried & tested) it also works through XamlReader.Load(), which is (sofar) the cleanest solution I've come up with.

But if anyone has anything better, I'd be glad to hear about it.

like image 715
Willem van Rumpt Avatar asked Dec 28 '25 21:12

Willem van Rumpt


2 Answers

Run.Text is backed by the private TextProperty which means you can't directly set its value without some reflection gimmicks, something like this:

        Run r=new Run();
        r.Text = "Moo";
        var field=r.GetType().GetField("TextProperty", BindingFlags.Static | BindingFlags.NonPublic);
        var dp=field.GetValue(null) as DependencyProperty;
        BindingOperations.SetBinding(r, dp, new Binding {...});

This is rather ugly, but perhaps it can be useful.

You can find various workarounds for this. This SO post uses a custom attached property to configure binding. The attached property is used because Run is a sealed class in Silverlight so you can't create you own Run that supports binding.

like image 104
Panagiotis Kanavos Avatar answered Dec 31 '25 09:12

Panagiotis Kanavos


The reason that it works in XAML but not in code-behind might be that there is a dependency property for Text, but it is private. It's a little bit 'black magic' to me though, so that's just a guess! This is a strange one, as in WPF the Run does inherit from FrameworkContentElement and has a SetBinding method...

Could you create a subclass of Run that contains a public DependencyProperty for text? I'm afraid I don't have the Silverlight dev tools to hand to try it out at the moment, but I'll try and take a look later.

like image 25
pete the pagan-gerbil Avatar answered Dec 31 '25 09:12

pete the pagan-gerbil