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
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);
}
}