65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF TextBlock 高亮显示

starIconstarIconstarIconstarIconstarIcon

5.00/5 (15投票s)

2018年2月9日

CPOL

1分钟阅读

viewsIcon

28177

downloadIcon

1076

如何使用附加属性高亮显示 TextBlock 文本

引言

我将在这里,不带任何双关语,介绍如何使用附加属性来高亮显示 TextBlock 中的文本,这些属性可以设置要高亮的文本及其背景和前景色。

TextBlockHighlighter

TextBlockHighlighter 是一个包含用于高亮显示 TextBlock 中文本的附加属性定义的类。第一个属性 Selection 用于指定 TextBlock 中将要高亮的文本。高亮显示是通过属性的回调方法,利用 Inlines 来完成的。

public static readonly DependencyProperty SelectionProperty =
    DependencyProperty.RegisterAttached("Selection", typeof(string), typeof(TextBlockHighlighter),
        new PropertyMetadata(new PropertyChangedCallback(SelectText)));

private static void SelectText(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d == null) return;
    if (!(d is TextBlock)) throw new InvalidOperationException("Only valid for TextBlock");

    TextBlock txtBlock = d as TextBlock;
    string text = txtBlock.Text;
    if (string.IsNullOrEmpty(text)) return;

    string highlightText = (string)d.GetValue(SelectionProperty);
    if (string.IsNullOrEmpty(highlightText)) return;

    int index = text.IndexOf(highlightText, StringComparison.CurrentCultureIgnoreCase);
    if (index < 0) return;

    Brush selectionColor = (Brush)d.GetValue(HighlightColorProperty);
    Brush forecolor = (Brush)d.GetValue(ForecolorProperty);

    txtBlock.Inlines.Clear();
    while (true)
    {
        txtBlock.Inlines.AddRange(new Inline[] {
                 new Run(text.Substring(0, index)),
                 new Run(text.Substring(index, highlightText.Length)) {Background = selectionColor,
                     Foreground = forecolor}
        });

        text = text.Substring(index + highlightText.Length);
        index = text.IndexOf(highlightText, StringComparison.CurrentCultureIgnoreCase);

        if (index < 0)
        {
            txtBlock.Inlines.Add(new Run(text));
            break;
        }
    }
}
Public Shared ReadOnly SelectionProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("Selection", GetType(String), GetType(TextBlockHighlighter),
                                            New PropertyMetadata(New PropertyChangedCallback
                                           (AddressOf SelectText)))

Private Shared Sub SelectText(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
    If d Is Nothing Then Exit Sub
    If TypeOf d IsNot TextBlock Then Throw New InvalidOperationException("Only valid for textBlock")

    Dim txtBlock As TextBlock = CType(d, TextBlock)
    Dim text As String = txtBlock.Text
    If String.IsNullOrEmpty(text) Then Exit Sub

    Dim highlightText As String = CStr(d.GetValue(SelectionProperty))
    If String.IsNullOrEmpty(highlightText) Then Exit Sub

    Dim index = text.IndexOf(highlightText, StringComparison.CurrentCultureIgnoreCase)
    If index < 0 Then Exit Sub

    Dim selectionColor As Brush = CType(d.GetValue(HighlightColorProperty), Brush)
    Dim forecolor As Brush = CType(d.GetValue(ForecolorProperty), Brush)

    txtBlock.Inlines.Clear()
    While True
        txtBlock.Inlines.AddRange(New Inline() {
                                      New Run(text.Substring(0, index)),
                                      New Run(text.Substring(index, highlightText.Length)) _
                                      With {.Background = selectionColor, .Foreground = forecolor}
                                      })

        text = text.Substring(index + highlightText.Length)
        index = text.IndexOf(highlightText, StringComparison.CurrentCultureIgnoreCase)

        If index < 0 Then
            txtBlock.Inlines.Add(New Run(text))
            Exit While
        End If
    End While
End Sub

由于附加属性仅供 TextBlock 独占使用,因此如果您尝试在任何其他元素上使用它,将会抛出异常。

在 XAML 设计器中显示的错误消息

还有另外两个附加属性可用于设置高亮文本的背景和前景色。

public static readonly DependencyProperty HighlightColorProperty =
    DependencyProperty.RegisterAttached("HighlightColor", typeof(Brush), typeof(TextBlockHighlighter),
        new PropertyMetadata(Brushes.Yellow, new PropertyChangedCallback(HighlightText)));
...

public static readonly DependencyProperty ForecolorProperty =
    DependencyProperty.RegisterAttached("Forecolor", typeof(Brush), typeof(TextBlockHighlighter),
        new PropertyMetadata(Brushes.Black, new PropertyChangedCallback(HighlightText)));
Public Shared ReadOnly HighlightColorProperty As DependencyProperty =
    DependencyProperty.RegisterAttached("HighlightColor", GetType(Brush), GetType(TextBlockHighlighter),
                                        New PropertyMetadata(Brushes.Yellow,
                                                             New PropertyChangedCallback
                                                             (AddressOf SelectText)))
...

Public Shared ReadOnly ForecolorProperty As DependencyProperty =
    DependencyProperty.RegisterAttached("Forecolor", GetType(Brush), GetType(TextBlockHighlighter),
                                        New PropertyMetadata(Brushes.Black,
                                                             New PropertyChangedCallback
                                                             (AddressOf SelectText)))

用法

要使用这些附加属性,只需添加对包含这些属性的命名空间的引用,并将它们应用于 TextBlock 元素即可。

<TextBlock Text="Awesome"
           local:TextBlockHighlighter.Selection="awe"
           local:TextBlockHighlighter.HighlightColor="Aquamarine"
           local:TextBlockHighlighter.Forecolor="Red"/>

您还可以绑定附加属性:在可下载的示例项目中,TextBlockHighlighter.Selection 属性绑定到类型为 string 的属性,该属性充当 ItemsControl 中显示的元素的过滤器。应用该属性的 TextBlockItemsControl 的数据模板的内容。

<ItemsControl Margin="10,10,10,0" Background="White"
              ItemsSource="{Binding Words}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Margin="10,2" FontWeight="Bold"
                       Text="{Binding}" 
                       local:TextBlockHighlighter.Selection="{Binding DataContext.Filter,
                Mode=OneWay, RelativeSource={RelativeSource AncestorType=Window}}"
                       local:TextBlockHighlighter.HighlightColor="LightGreen"
                       local:TextBlockHighlighter.Forecolor="Teal"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

结论

希望本文档提供的信息对您有所帮助,或者在某个时刻对您有所用处。我在这里采用的方法,使用 Inlines 和 string 来定义选择,是受到一篇关于同一主题的文章中的 建议 的启发。感谢 Bruce Greene 提出的良好建议。

历史

  • 2018年2月9日:初始发布
© . All rights reserved.