1

I have a list of phrases which needs to be displayed. These phrases have a static text and a variable number of bits that need to be highlighted on the screen (bold, colored differently).

Here's a sample of how this would look like if I am to build everything from xaml.

    <TextBlock Grid.Row="2">
        <Run Text="Your"/>
        <Run Text="{Binding Text1}"/>
        <Run Text="has a limit of $"/>
        <Run Text="{Binding Limit}" FontWeight="Bold" Foreground="Red"/>
        <Run Text="for period "/>
        <Run Text="{Binding StartDate}" FontWeight="Bold" Foreground="Blue"/>
        <Run Text=" : "/>
        <Run Text="{Binding EndDate}" FontWeight="Bold" Foreground="Blue"/>
        <Run Text=". Your up to date expenses are $"/>
        <Run Text="{Binding Expenses}" FontWeight="Bold" Foreground="Red"/>
    </TextBlock>

    <TextBlock Grid.Row="3">
        <Run Text="Your"/>
        <Run Text="{Binding Text2}"/>
        <Run Text="has a limit of $"/>
        <Run Text="{Binding Limit2}" FontWeight="Bold" Foreground="Red"/>
        <Run Text="for period "/>
    </TextBlock>

What I would like to achieve is to somehow bind the text with {0} in it and an bind an ItemsSource that will set the Inlines for a TextBlock, and further, bind an ItemsSource maybe for styles (font weight and text color) each inline should have:

Text: Your {0} has a limit of ${1} for period.

Values to populate inlines: abc,1000

Styles to apply {none,none}, {bold,red}

Is this possible in the first place? And if so, can you please point me in the right direction or give me a few hints?

Thanks.

1
  • 1
    you can try with ItemsControl bound to list of parts where ItemsPanel is horizontal StackPanel (for example) and ItemTemplate is TextBlock Commented Feb 27, 2015 at 12:44

2 Answers 2

1

I would create a custom TextBlock descendant for this, and create the inlines programmatically.

First, create a model to control the display of your text:

public class TextModel
{
    public string Text { get; set; }
    public Color Color { get; set; }
    public FontWeight Weight { get; set; }
}

You might want to implement INotifyPropertyChanged on this, although that will complicate things later.

Next, you need a collection of these:

public class TextModelCollection : ObservableCollection<TextModel>
{
}

Finally, create a custom class derived from TextBlock:

public class MyCustomTextBlock : TextBlock
{
    public static readonly DependencyProperty ItemsProperty =
        DependencyProperty.Register("Items", typeof(TextModelCollection),
        typeof(MyCustomTextBlock), new PropertyMetadata(OnItemsChanged));

    public TextModelCollection Items
    {
        get
        {
            return (TextModelCollection) GetValue(ItemsProperty);
        }
        set
        {
            SetValue(ItemsProperty, value);
        }
    }

    public MyCustomTextBlock()
    {
        RefreshInlines();
    }

    static void OnItemsChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        ((MyCustomTextBlock) d).RefreshInlines();
    }
}

Then you just need a method (called RefreshInlines here) that will refresh the text block's inlines collection when the custom property changes.

void RefreshInlines()
{
    Inlines.Clear();
    foreach (TextModel text in Items)
    {
        var run = new Run(text.Text);
        run.Foreground = new SolidColorBrush(text.Color);
        run.FontWeight = text.Weight;
        Inlines.Add(run);
    }
}

As TextModelCollection is an observable collection, you will need to register for list changes so that you can refresh the inlines when items are added or removed. I haven't shown that code here, but it would basically tie-in to the OnItemsChanged method.

Sign up to request clarification or add additional context in comments.

1 Comment

This sounds like it might just work exactly how I need. I`ll give it a try. Thanks.
0

It's actually two questions:

First

You are looking for MultiBinding and StringFormat:

This one is for when the Text starts with a static text:

<TextBlock>
   <TextBlock.Text>
       <MultiBinding StringFormat="Write Static Text Here {1} Something else {1}">
          <Binding Path="Text2" />
          <Binding Path="Text2" />
       </MultiBinding>
   </TextBlock.Text>
</TextBlock>

And this one is for when the Text starts with a variable text:

<TextBlock>
   <TextBlock.Text>
       <MultiBinding StringFormat="{}{0} Write Static Text Here {1} Something else">
          <Binding Path="Text2" />
          <Binding Path="Text2" />
       </MultiBinding>
   </TextBlock.Text>
</TextBlock>

Second

You need to use anything like ItemsControl (ListBox DataGrid etc)

<ItemsControl ItemsSource="{Binding MyList}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
             put anything here to display as an element of MyList
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

You also need to create a collection for MyList in the DataContext of window. for example:

public MainWindow()
{
    InitializeComponent();
    var vm = new MainVm();
    DataContext = vm;
}

this MainVm should derive from DependencyObject and contains something like:

public ObservableCollection<string> MyList { get { return _myList; } }
private ObservableCollection<string> _myList = new ObservableCollection<string>();

for more information, google MVVM.

2 Comments

Yes, but on top of this, i need to make the list of bindings containing Text1,Text2 bind-able somehow, and also add font weight and color to elements from that list ... that is my challenge.
Oh I missed that part. Please take a look at the updated answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.