How to highlight selected parts of a linked TextBlock?

I have a TextBlock binding to a property. However, I would like to highlight some words in the text. What is the easiest way to do this? FYI, I am new to WPF.

+4
source share
1 answer

Bold single words actually involve creating more inline elements, so you can't just snap a string to TextBlock Text and do it.

What I did for this in the past is a subclass of TextBlock that has a custom property that I bind to. When this property is bound, I clear the Inlines of the underlying TextBlock, and then use an algorithm that parses the new string value, creating either simple Runs, Bolds, Hyperlinks, etc.

Here is an example of the code I wrote for my experimental Twitter client that detects URLs, email, and @pattern and creates hyperlinks for them. Regular text is built into normal mode:

[ContentProperty("StatusText")] public sealed class StatusTextBlock : TextBlock { #region Fields public static readonly DependencyProperty StatusTextProperty = DependencyProperty.Register( "StatusText", typeof(string), typeof(StatusTextBlock), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.None, StatusTextBlock.StatusTextPropertyChangedCallback, null)); private static readonly Regex UriMatchingRegex = new Regex(@"(?<url>[a-zA-Z]+:\/\/[a-zA-Z0-9]+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,5}(:[0-9]{1,5})?([a-zA-Z0-9_\-\.\~\%\+\?\=\&\;\|/]*)?)|(?<emailAddress>[^\s] +@ [a-zA-Z0-9]+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,5})|(?<toTwitterScreenName>\@[a-zA-Z0-9\-_]+)", RegexOptions.Compiled); #endregion #region Constructors public StatusTextBlock() { } #endregion #region Type specific properties public string StatusText { get { return (string)this.GetValue(StatusTextBlock.StatusTextProperty); } set { this.SetValue(StatusTextBlock.StatusTextProperty, value); } } #endregion #region Helper methods internal static IEnumerable<Inline> GenerateInlinesFromRawEntryText(string entryText) { int startIndex = 0; Match match = StatusTextBlock.UriMatchingRegex.Match(entryText); while(match.Success) { if(startIndex != match.Index) { yield return new Run(StatusTextBlock.DecodeStatusEntryText(entryText.Substring(startIndex, match.Index - startIndex))); } Hyperlink hyperLink = new Hyperlink(new Run(match.Value)); string uri = match.Value; if(match.Groups["emailAddress"].Success) { uri = "mailto:" + uri; } else if(match.Groups["toTwitterScreenName"].Success) { uri = "http://twitter.com/" + uri.Substring(1); } hyperLink.NavigateUri = new Uri(uri); yield return hyperLink; startIndex = match.Index + match.Length; match = match.NextMatch(); } if(startIndex != entryText.Length) { yield return new Run(StatusTextBlock.DecodeStatusEntryText(entryText.Substring(startIndex))); } } internal static string DecodeStatusEntryText(string text) { return text.Replace("&gt;", ">").Replace("&lt;", "<"); } private static void StatusTextPropertyChangedCallback(DependencyObject target, DependencyPropertyChangedEventArgs eventArgs) { StatusTextBlock targetStatusEntryTextBlock = (StatusTextBlock)target; targetStatusEntryTextBlock.Inlines.Clear(); string newValue = eventArgs.NewValue as string; if(newValue != null) { targetStatusEntryTextBlock.Inlines.AddRange(StatusTextBlock.GenerateInlinesFromRawEntryText(newValue)); } } #endregion } 
+6
source

All Articles