Vaccano
Vaccano

Reputation: 82437

Set the content of a TextBlock

Say I have a TextBlock that looks like this:

<TextBlock TextWrapping="Wrap" >
    Text in <Run Foreground="Red">red</Run> and <Run Foreground="Red">more</Run>
</TextBlock>

That works fine and the text is shown in red as you think it would. However, in my real example this text:

 Text in <Run Foreground="Red">red</Run> and <Run Foreground="Red">more</Run>

Comes from a service call. (Including the tags.)

Is there a way to supply this text to the TextBlock at runtime?

Upvotes: 1

Views: 1004

Answers (2)

Vaccano
Vaccano

Reputation: 82437

I thought I would post the control that I made from King Kong's answer. (Just in case it is useful to someone else.)

public class FormatBindableTextBlock : TextBlock
{
    private static readonly ParserContext parserContext;

    static FormatBindableTextBlock()
    {
        parserContext = new System.Windows.Markup.ParserContext();
        parserContext.XmlnsDictionary[""] = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
        parserContext.XmlnsDictionary["x"] = "http://schemas.microsoft.com/winfx/2006/xaml";
    }

    public static readonly DependencyProperty FormattedContentProperty =
        DependencyProperty.Register("FormattedContent", typeof(string), typeof(FormatBindableTextBlock), new UIPropertyMetadata(null, OnFormattedContentPropertyChanged));

    public string FormattedContent
    {
        get { return (string)GetValue(FormattedContentProperty); }
        set { SetValue(FormattedContentProperty, value); }
    }

    private static void OnFormattedContentPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        FormatBindableTextBlock textBlock = sender as FormatBindableTextBlock;

        if (textBlock == null)
            return;

        string newFormattedContent = e.NewValue as string;
        if (string.IsNullOrEmpty(newFormattedContent)) 
            newFormattedContent = "";

        newFormattedContent = "<TextBlock>" + newFormattedContent + "</TextBlock>";

        TextBlock tbl = System.Windows.Markup.XamlReader.Parse(newFormattedContent, parserContext) as TextBlock;
        textBlock.Inlines.Clear();
        textBlock.Inlines.AddRange(tbl.Inlines.ToList());

    }

}

Upvotes: 2

King King
King King

Reputation: 63347

In fact you have to convert all the input text into Inlines collection (of type TextElementCollection). However doing so requires parsing the input text yourself which is not easy. So why not use the existing parser supported by XamlReader. By using this class, you can parse a XAML code to get an instance of a TextBlock from which you can get the Inlines collection and add that for your actual TextBlock. Here is the code:

var text = "<TextBlock>Text in <Run Foreground=\"Red\">red</Run> and <Run Foreground=\"Red\">more</Run></TextBlock>";
var pc = new System.Windows.Markup.ParserContext();
pc.XmlnsDictionary[""] = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
pc.XmlnsDictionary["x"] = "http://schemas.microsoft.com/winfx/2006/xaml";
var tbl = System.Windows.Markup.XamlReader.Parse(text, pc) as TextBlock;
yourTextBlock.Inlines.Clear();            
yourTextBlock.Inlines.AddRange(tbl.Inlines.ToList());

Your actual input text should be wrapped in the pair <TextBlock> & </TextBlock> before being used by the next code.

Upvotes: 2

Related Questions