3

I am trying to format a Tweet using Data Binding. What I need to do is split the Text value of the tweet based on what type of content it is.

text = "This is a Tweet with a hyperlink http://www.mysite.com"

I need to add some color formatting to the http://... portion of the text value.

Here's the kicker, I'd like to do this using only XAML Data Binding.

 <TextBlock x:Name="Tweet1" FontWeight="Bold" Height="207.236" 
    LineHeight="55" TextAlignment="Left" TextWrapping="Wrap" 
    Width="1614.646" Text="{Binding XPath=/statuses/status[2]/text}" 
    FontSize="56" FontFamily="Segoe Book" 
    Foreground="{DynamicResource TextColor-Gray}" />

// needs to end up looking like

<TextBlock x:Name="Tweet1" FontWeight="Bold" ... FontSize="56" FontFamily="Segoe Book">
  <Run Foreground="{DynamicResource TextColor-Gray}" >This is a Tweet with a hyperlink</Run>
<Run Foreground="{DynamicResource TextColor-Pink}" >http://www.mysite.com</Run>
</TextBlock>

Here is a Regex I could use to split the text value, but I'm trying to use strictly DataBinding.

Regex regUrl = new Regex(@"/http:\/\/\S+/g");

Suggestions?

Amicable
  • 3,115
  • 3
  • 49
  • 77
discorax
  • 1,487
  • 4
  • 24
  • 39

2 Answers2

2

I'm using MVVMLight. What I've done is to capture the Loaded event of the TextBlock, and route it to a "converter".

using System.Collections.Generic;
using System.Windows.Documents;
using System.Windows.Controls;

using GalaSoft.MvvmLight.Command;

namespace Converters
{
    public class MyInlineConverter
    {
        public RelayCommand<TextBlock> ConvertTextToInlinesCommand { get; private set; }

        public MyInlineConverter()
        {
            ConvertTextToInlinesCommand = new RelayCommand<TextBlock>(textBlock => convertTextToInlines(textBlock));
        }

        private static void convertTextToInlines(TextBlock textBlock)
        {
            foreach (Run run in textToInlines(textBlock.Text))
                textBlock.Inlines.Add(run);
        }

        private static IEnumerable<Run> textToInlines(string text)
        {
            List<Run> retval = new List<Run>();
            // Perform your conversion here.
            return retval;
        }
    }
}

If you add an instance of this class to your static resources, like so:

<converters:TMTInlineConverter x:Key="InlineConverter" />

then you can invoke the converter from your TextBlock as follows:

                        <TextBlock Text="{Binding MyPath}" TextWrapping="Wrap">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="Loaded">
                                    <cmdex:EventToCommand Command="{Binding Source={StaticResource InlineConverter}, Path=ConvertTextToInlinesCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}" />
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </TextBlock>

Apologies if you're not using MVVMLight. If you're not, I'll leave the translation as an exercise for the reader. :)

Rob
  • 21
  • 2
0

You can't bind to Text and substitute with Runs because Text is of type String. Instead, you'd need to bind Inlines and provide a converter that parses the text (using your regex, for example) and produces the appropriate Inlines:

<TextBlock Inlines="{Binding XPath=/statuses/status[2]/text, Converter={StaticResource InlineConverter}}"/>
Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • That what I figured. Thanks for confirming. I'll post my converter when I'm done building it. – discorax Oct 22 '10 at 22:56
  • 4
    You can't bind to Inlines. "Inlines property is Read-Only and can not be set by markup" Any other suggestions? – discorax Oct 22 '10 at 23:35
  • Your solution won't work, but it lead me to this answer which I am trying to work through now. http://stackoverflow.com/questions/1959856/data-binding-the-textblock-inlines – discorax Oct 25 '10 at 17:12