WPF TextBlock 高亮显示





5.00/5 (15投票s)
如何使用附加属性高亮显示 TextBlock 文本

引言
我将在这里,不带任何双关语,介绍如何使用附加属性来高亮显示 TextBlock
中的文本,这些属性可以设置要高亮的文本及其背景和前景色。
TextBlockHighlighter
TextBlockHighlighter
是一个包含用于高亮显示 TextBlock
中文本的附加属性定义的类。第一个属性 Selection
用于指定 TextBlock
中将要高亮的文本。高亮显示是通过属性的回调方法,利用 Inline
s 来完成的。
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
中显示的元素的过滤器。应用该属性的 TextBlock
是 ItemsControl
的数据模板的内容。
<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>
结论
希望本文档提供的信息对您有所帮助,或者在某个时刻对您有所用处。我在这里采用的方法,使用 Inline
s 和 string
来定义选择,是受到一篇关于同一主题的文章中的 建议 的启发。感谢 Bruce Greene 提出的良好建议。
历史
- 2018年2月9日:初始发布