PETZOLD BOOK BLOG

Charles Petzold on writing books, reading books, and exercising the internal UTM


Recent Entries
< PreviousBrowse the ArchivesNext >
Subscribe to the RSS Feed

A Data Binding to the Text Property of Run?

April 15, 2013
New York, NY

Sometimes a programmer will encounter a situation where it's convenient to embed a changeable data value in a paragraph of text, and for this paragraph to re-wrap itself when the text representation of this data value acquires a different character width.

Of course, in any XAML-based environment (such as WPF, Silverlight, Windows Phone, or Windows 8), it would be nice if this could be done in markup rather than code. For example, here's a simple mock-up of what you might want, using a Slider as the source for the binding and the Binding object represented as a XAML markup extension on the Text property of a Run element embedded as content in the TextBlock (highlighted here in red):

<Page
    x:Class="App12.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel>
            <TextBlock FontSize="48"
                       TextWrapping="Wrap"
                       Width="500">
                This is an experiment to determine if we can embed a 
                <Italic>Run</Italic> element in a <Italic>TextBlock</Italic> 
                with a binding to a <Italic>Slider</Italic> so the binding
                can display the <Italic>Slider</Italic> value of
                <Run Text="{Binding ElementName=slider, Path=Value}" />
                and we can watch the rest of paragraph wrap based on the 
                character width of that value.
            </TextBlock>
            
            <Slider Name="slider"
                    Orientation="Horizontal"
                    Maximum="1000"
                    StepFrequency="0.1"
                    Margin="96" />
        </StackPanel>
    </Grid>
</Page>

But the problem is: You can't do it. The target of a Binding object must be backed by a dependency property. Unlike the Text property of TextBlock, the Text property of Run is not backed by a dependency property. And so, when I was writing about Windows 8 programming in Programming WIndows, 6th edition, I tried such a binding once again, and once again it did not work, as it did not work many years ago when I first tried it in WPF, or when I've tried it since then. The discussion why this doesn't work (and a simple workaround) appears in pages 87 – 89 of my book.

During the past couple weeks, however, I've been preparing for a live presentation about Windows 8 programming, and I decided to use this as an example that clearly demonstrates that binding targets must be dependency properties.

Except that this time the program worked! And here is a screenshot of a program that incorporates the XAML shown above running under Windows 8:

Sure enough, as you manipulate the Slider, the paragraph re-wraps itself based on the character width of the value.

I'm flabbergasted. If you try attaching a Binding element to a property in code by calling the SetBinding method, you'll prove to yourself beyond a shadow of a doubt that the binding target must indeed be a dependency property.

And yet, this works. It didn't work at one time in Windows 8 (because I definitely tried it) but it works now. Obviously there must be some finangling going on — some "hanky-panky," if you will, some "fiddle-diddle," some "funky-monkey" — that circumvents the normal binding mechanism and allows a binding that targets the Run property of Text.

I'm not sure how I feel about this. APIs require consistent rules. They shouldn't exhibit anomalies. We shouldn't have to test every possibility to determine if something works. Whether something works or not should be evident from first principles.

What about the other properties of TextElement and its derivatives? Do we now need to test those to determine if they accept data bindings or not? If the rules are violated here, where else are they violated?

In this particular case, wouldn't it have made more sense to add dependency properties to TextElement and its derivatives, much like the dependency properties in Geometry and its related classes?


Comments:

I know that this was "broken" for a while in WPF and Windows Phone's Silverlight, too.

But at some point it worked if you explicitly specified it as Mode=OneWay. I haven't tried without that, so i'm not sure when it started working.

John G, Mon, 15 Apr 2013 13:47:47 -0400

Starting in the .NET Framework 4, the Text property of the Run object is a dependency property, which means that you can bind the Text property to a data source. The Text property fully supports one-way binding in FlowDocumentReader and other controls that display read-only text. For more information about data binding, see Data Binding Overview.

http://msdn.microsoft.com/en-us/library/system.windows.documents.run.text.aspx

— majocha, Tue, 16 Apr 2013 12:04:04 -0400

Unless I'm missing something, in the Windows Runtime (which is not .NET 4) the Run property is not backed by a dependeny property. — Charles


Recent Entries
< PreviousBrowse the ArchivesNext >
Subscribe to the RSS Feed

(c) Copyright Charles Petzold
www.charlespetzold.com