Как выделить части связанного TextBlock жирным шрифтом?

У меня есть TextBlock, привязанный к свойству. Тем не менее, я хотел бы выделить жирным шрифтом некоторые слова в тексте. Как это сделать проще всего? К вашему сведению, я новичок в WPF.


person bsh152s    schedule 14.10.2009    source источник


Ответы (1)


Выделение жирным шрифтом отдельных слов на самом деле означает создание дополнительных встроенных элементов, поэтому вы не можете просто привязать строку к тексту TextBlock и сделать это.

Что я сделал для этого в прошлом, так это создал подкласс TextBlock, который имеет настраиваемое свойство, к которому я привязываюсь. Когда это свойство привязано, я очищаю Inlines базового TextBlock, а затем использую алгоритм, который анализирует новое строковое значение, создавая простые прогоны, полужирные шрифты, гиперссылки и т. д.

Вот пример кода, который я написал для своего экспериментального клиента Twitter, который обнаруживает URL-адреса, электронные письма и шаблон @ и создает для них гиперссылки. Обычный текст встраивается как обычные прогоны:

[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
}
person Drew Marsh    schedule 14.10.2009
comment
можете ли вы раскрасить текст по-другому с этим подходом? - person Aran Mulholland; 15.10.2009
comment
Конечно, вы просто устанавливаете для свойства Foreground экземпляра Run любую кисть, которую хотите. - person Drew Marsh; 15.10.2009
comment
Вы когда-нибудь пытались использовать текстовое поле с такими же вещами, текстовое поле не имеет встроенного свойства, поэтому, я полагаю, вам придется использовать расширенное текстовое поле. - person Aran Mulholland; 15.10.2009
comment
Да, вы должны использовать RichTextBox, а затем манипулировать содержимым через экземпляр FlowDocument так же, как я манипулирую встроенными строками TextBlock. - person Drew Marsh; 15.10.2009