Home > Software design >  WPF C# TextBlock. How to format textblock text programatically to format foreground color of certain
WPF C# TextBlock. How to format textblock text programatically to format foreground color of certain

Time:09-13

Problem:
I have WPF TextBlock with dynamically changed text. This text contains words that are color names.
For example:

MyTextBlock.Text = "This is some dynamic text that contains red, green and yellow words inside it.";

Result should be rendered so all "red", "green" and "yellow" words are formatted with their color.


Note: Text is dynamically changed so static formatting is not an option.)

CodePudding user response:

You can take benefit from Inline collection property inside TextBlock to customize the content and set it dynamically..

<TextBlock
    x:Name="MyTextBlock"
    Height="100"
    Padding="8"
    FontSize="18"
    TextWrapping="Wrap" />

You would do something like this in code behind..

{
    InitializeComponent();
    var input = "This is some dynamic text that contains Red and green and yellow words inside it.";
    UpdateTextBoxWithColoredText(MyTextBlock, input, _colors);
}

Where UpdateTextBoxWithColoredText is

private void UpdateTextBoxWithColoredText(TextBlock textBlock,
    string input, List<string> colors)
{
    var list = input
        .Split(' ')
        .ToList();
    var stringBuilder = new StringBuilder();
    foreach (var currentString in list)
    {
        if (colors.Contains(currentString.ToLower()))
        {
            textBlock.Inlines.Add($"{stringBuilder} ");
            stringBuilder.Clear();
            var run = new Run(currentString)
            {
                Foreground = ColorName2Brush(currentString.ToLower())
            };
            textBlock.Inlines.Add(run);
            textBlock.Inlines.Add(" ");
        }
        else
            stringBuilder.Append($"{currentString} ");
    }

    textBlock.Inlines.Add($"{stringBuilder} ");
}

private readonly List<string> _colors = new() { "red", "green", "yellow" };

private Brush ColorName2Brush(string colorName) =>
    colorName switch
    {
        "green" => ToSolidColorBrush("#00FF00"),
        "yellow" => ToSolidColorBrush("#FFFF00"),
        "red" => ToSolidColorBrush("#FF0000"),
        _ => ToSolidColorBrush("#000000")
    };

private SolidColorBrush ToSolidColorBrush(string hex)
{
    try
    {
        return (SolidColorBrush)new BrushConverter().ConvertFrom(hex);
    }
    catch (Exception)
    {
        return (SolidColorBrush)new BrushConverter().ConvertFrom("#000000");
    }
}

Sample output

enter image description here

Note: punctuations are not handled in the solution above, also linebreaks (you can do textblock.Inlines.Add(new LineBreak()); or stringBuilder.AppendLine();), this is sort of string processing that you can do it in your behalf :)

CodePudding user response:

The very first answer contains a great solution but there is a lack of dynamic update, so try to add TargetUpdated event to the TextBlock you are using:

<TextBlock x:Name="MyTextBlock"
           Text="{Binding YourTextProperty, NotifyOnTargetUpdated=True}" 
           TargetUpdated="OnTargetUpdated"/>

Then exploit the TextBoxWithColoredText method from the same answer:

private void OnTargetUpdated(object sender, DataTransferEventArgs e)
{
    if (sender is TextBlock textBlock)
    {
        TextBoxWithColoredText(textBlock, textBlock.Text, _color);
    }
}
  • Related