views:

580

answers:

2

I have a TextBlock binding as follows in my ControlTemplate.

<TextBlock Grid.Column="1" VerticalAlignment="Center"
 FontSize="16" FontFamily="Arial" FontWeight="Bold"
 Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=ButtonText}">
</TextBlock>

When I set ButtonText as follows with , it doesn't work. It doesn't display in separate line.

ButtonText="Change<LineBreak/> Casette"

How to fix this? Appreciate your help, please provide me with sample code.

A: 

I used this code to obtain what you want. This is the XAML:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="1" VerticalAlignment="Center"
           FontSize="16" FontFamily="Arial" FontWeight="Bold"
           Text="{Binding Path=ButtonText}">
    </TextBlock>
</Grid>

and this is the code behind. To make the example simplier, I don't create a ViewModel class:

    public Window1()
    {
        InitializeComponent();
        DataContext = this;
        ButtonText = "Change\r\nCasette";
    }


    public string ButtonText
    {
        get { return (string)GetValue(ButtonTextProperty); }
        set { SetValue(ButtonTextProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ButtonText.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ButtonTextProperty =
        DependencyProperty.Register("ButtonText", typeof(string), typeof(Window1), new UIPropertyMetadata(""));
Maurizio Reginelli
Thanks for your reply, I am changing it from XAML. Why doesn't it work from XAML? Should it be done from code behind?
Vin
Use this string: "ChangeCasette"
Maurizio Reginelli
+1  A: 

A TextBlock displays the contents of its Inlines property. The Text property exists only as a convenience (though it's a significant one): if you set the Text property, the TextBlock will create a Run, set its content to the string you've provided, and save it in the Inlines collection.

When you set the content of a TextBlock element in XAML, the XamlReader populates the Inlines collection directly rather than through the Text property. It parses text nodes into Run objects, and elements as usual for XAML. So this:

<TextBlock>
   Line1<LineBreak/>Line2
</TextBlock>

is treated as though it were actually this:

<TextBlock>
   <Run>Line1</Run>
   <LineBreak/>
   <Run>Line2</Run>
</TextBlock>

Note, by the way, that if you try to set the Text property explicitly:

<TextBlock>
   <TextBlock.Text>
      Line1<LineBreak/>Line2
   </TextBlock.Text>
</TextBlock>

you'll get an exception, because the XamlReader will try to create a LineBreak object, and the Text property can only contain a string.

Your binding isn't working the way you want it to because it's explicitly setting the Text property to a string. This doesn't get parsed as XAML (and good thing, too). And so what's displaying in the TextBlock is the content of that string.

So there are basically two ways to accomplish what you're trying to accomplish. In your case, you probably can just get away with embedding a newline into the string.

But this is trickier than it looks if you're doing it from XAML. Because XAML is XML, and XML does some funny things to whitespace. You're OK if you set it explicitly in an attribute using XML character entities, e.g.:

<TextBlock Text="Line 1&#x0d;&#x0a;Line 2"/>

But that won't work if you do it this way:

<TextBlock>
   <TextBlock.Text>
      Line 1&#x0d;&#x0a;Line 2
   </TextBlock.Text>
</TextBlock>

because the XML parser normalizes whitespace in element content. That CR/LF pair gets turned into a single space, and that's what gets into the text property.

If you're using binding, you don't need to worry about any of this XML stuff (unless you're binding to the contents of an XML document!). You can just put \r\n into the property value.

The other way to do this is to directly populate the TextBlock's Inlines property. But you can't do this via binding, since Inlines isn't a dependency property - in fact, it's read-only, and you can only populate it by calling its Add or AddRange methods.

Robert Rossney