耀世微光 发表于 2023-8-28 08:53:38

WPF使用TextBlock实现查找结果高亮显示

在应用开发过程中,经常遇到这样的需求:通过关键字查找数据,把带有关键字的数据显示出来,同时在结果中高亮显示关键字。在web开发中,只需在关键字上加一层标签,然后设置标签样式就可以轻松实现。
在WPF中显示文本内容通常采用TextBlock控件,也可以采用类似的方式,通过内联流内容元素Run达到同样的效果:
<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>需要注意的是每个Run之间不要换行,如果换行的话,每个Run之间会有间隙,看起来像增加了空格。
通过这种方式实现查找结果中高亮关键字,需要把查找结果拆分成三部分,然后绑定到Run元素的Text属性,或者在后台代码中使用TextBlock的Inlines属性添加Run元素
textBlock1.Inlines.Add(new Run("hel"));
textBlock1.Inlines.Add(new Run("lo ") { Foreground=new SolidColorBrush(Colors.Red)});
textBlock1.Inlines.Add(new Run("world"));这种方法虽然可以达到效果,但显然与MVVM的思想不符。接下来本文介绍一种通过附加属性实现TextBlock中指定内容高亮。

技术要点与实现

通过TextEffect的PositionStart、PositionCount以及Foreground属性设置字符串中需要高亮内容的起始位置、长度以及高亮颜色。定义附加属性允许TextBlock设置需要高亮的内容位置以及颜色。

[*]首先定义类ColoredLettering(并不要求继承DependencyObject)。
[*]在ColoredLettering中注册自定义的附加属性,注册附加属性方式与注册依赖属性类似,不过附加属性是用DependencyProperty.RegisterAttached来注册。
[*]给附加属性注册属性值变化事件,事件处理逻辑中设置TextEffect的PositionStart、PositionCount以及Foreground实现内容高亮。
public class ColoredLettering{<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>public static void SetColorStart(TextBlock textElement, int value)<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>{<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>textElement.SetValue(ColorStartProperty, value);<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>}<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>public static int GetColorStart(TextBlock textElement)<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>{<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>return (int)textElement.GetValue(ColorStartProperty);<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>}<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>// Using a DependencyProperty as the backing store for ColorStart.This enables animation, styling, binding, etc...<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>public static readonly DependencyProperty ColorStartProperty =<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>DependencyProperty.RegisterAttached("ColorStart", typeof(int), typeof(ColoredLettering), new FrameworkPropertyMetadata(0, OnColorStartChanged));<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>private static void OnColorStartChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>{<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>TextBlock textBlock = d as TextBlock;<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>if (textBlock != null)<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>{<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>if (e.NewValue == e.OldValue) return;<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>if (e.NewValue is int)<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>{<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>int count = GetColorLength(textBlock);<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>Brush brush = GetForeColor(textBlock);<TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock><TextBlock FontSize="20">
    <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
</TextBlock>if ((int)e.NewValue
页: [1]
查看完整版本: WPF使用TextBlock实现查找结果高亮显示