Bindable Run

Since the initial release of WPF, Run.Text has been a normal CLR property. This has meant that Run.Text lacks all the benefits of the WPF dependency property system, most notably the ability to be bound. In some cases, one could substitute Runs for TextBlocks, which can be bound to; however this can quickly create text flow problems (see example below). The omission of a bindable Run has given birth to many homebrew solutions (eg. here and here). Feeble workarounds and custom solutions are no longer necessary. In WPF 4.0 we have done the work to back Run.Text with a dependency property.

 

 

Bindable Run API

The property Run.Text has been converted to a dependency property . Now Run.Text enjoys all of the benefits of full dependency properties (binding, styling, templating, etc…).

 

<Window x:Class="TextBlogDWriteDemo.Window1"

       xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

       xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"

       Title="Window1">

    <Window.Resources>

        <TextBox x:Key="DataStore1" Text="how text does not

                                          flow correctly"/>

        <TextBox x:Key="DataStore2" Text="This is an example

  of how text flows correctly when only

  using bound Runs"/>

    </Window.Resources>

        <FlowDocument>

            <Paragraph>

                <Run Text="This is an example of"/>

                <TextBlock Text="{Binding Source=

                   {StaticResource DataStore1},

                   Path=Text}"/>

                <Run Text="when using a combination of Runs

                           and TextBlock"/>

            </Paragraph>

            <Paragraph>

                <Run Text="{Binding Source={StaticResource

                           DataStore2}, Path=Text}"/>

            </Paragraph>

        </FlowDocument>

</Window>

BindableRun

This is a screenshot of the text produced by the above XAML. Notice the spacing issues which are fixed by binding to a Run as opposed to a TextBlock.

Bindable Run Usage

 

One way data binding is fully supported. A Run can be bound to a data source and the content of the Run will reflect the value of what it is bound to. The bound Run will receive and display any changes that occur in the data source.

Two way data binding is partially supported. If a bound Run is updated via calls to the WPF property system, the data source which the Run is bound to will reflect the changes to the Run. On the other hand, if a bound Run is updated via a RichTextBox or the text object model, the Run will lose its binding.

 

- Chipalo

Comments

  • Anonymous
    October 27, 2009
    Sweet! I never liked having to dig out the homebrew code whenever I start playing around with a new project.

  • Anonymous
    October 27, 2009
    This is great news.  I ended up resorting to 'binding' with xslt for FlowDocument stuff previously so this is a huge improvement.  Thanks for listening to your customers on this one!

  • Anonymous
    April 12, 2010
    The comment has been removed

  • Anonymous
    April 13, 2010
    Po- Short answer… This example doesn’t really show justification. That is a byproduct of how the Run is doing linebreaking. Long answer… When reexamining the code snippet, I realize that I could have more clearly conveyed the advantages of a BindableRun. The purpose of this example was to show a scenario when one would like data bound content in the midst of static content. Imagine a report where each page has a footer which reads, “this is the ___ page of this report.” In previous versions of the framework, the only way to do this would be to use a databound TextBlock. If the stars are aligned and the space provided for your footer is perfect, the text spacing may come out correct. In the majority of cases, due to the behavior of TextBlock and Run, the   output will look very bad. The correct way to accomplish this would to be use three runs where one is databound. This is now possible in WPF4. I have included updated sample code so that you can play with it and see some of the spacing issues I briefly mentioned. <Window x:Class="TextBlogDWriteDemo.Window1"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        Title="Window1">    <Window.Resources>        <TextBox x:Key="DataStore1" Text="how text does not                                          flow correctly"/>        <TextBox x:Key="DataStore2" Text="This is an example  of how text flows correctly when only  using bound Runs"/>                <TextBox x:Key="DataStore3" Text="how text flows correctly"/>    </Window.Resources>    <FlowDocument>        <Paragraph>            <Run Text="This is an example of"/>            <TextBlock Text="{Binding Source=                   {StaticResource DataStore1},                   Path=Text}"/>            <Run Text="when using a combination of Runs                           and TextBlock"/>        </Paragraph>        <Paragraph>            <Run Text="This is an example of"/>            <Run Text="{Binding Source={StaticResource                           DataStore3}, Path=Text}"/>            <Run Text="when using a combination of Runs and TextBlock"/>        </Paragraph>    </FlowDocument> </Window>