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
{
public static void SetColorStart(TextBlock textElement, int value)
{
textElement.SetValue(ColorStartProperty, value);
}
public static int GetColorStart(TextBlock textElement)
{
return (int)textElement.GetValue(ColorStartProperty);
}
// Using a DependencyProperty as the backing store for ColorStart. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ColorStartProperty =
DependencyProperty.RegisterAttached("ColorStart", typeof(int), typeof(ColoredLettering), new FrameworkPropertyMetadata(0, OnColorStartChanged));
private static void OnColorStartChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = d as TextBlock;
if (textBlock != null)
{
if (e.NewValue == e.OldValue) return;
if (e.NewValue is int)
{
int count = GetColorLength(textBlock);
Brush brush = GetForeColor(textBlock);
if ((int)e.NewValue <= 0 || count <= 0 || brush == TextBlock.ForegroundProperty.DefaultMetadata.DefaultValue) return;
if (textBlock.TextEffects.Count != 0)
{
textBlock.TextEffects.Clear();
}
TextEffect textEffect = new TextEffect()
{
Foreground = brush,
PositionStart = (int)e.NewValue,
PositionCount = count
};
textBlock.TextEffects.Add(textEffect);
}
}
}
public static void SetColorLength(TextBlock textElement, int value)
{
textElement.SetValue(ColorLengthProperty, value);
}
public static int GetColorLength(TextBlock textElement)
{
return (int)textElement.GetValue(ColorLengthProperty);
}
// Using a DependencyProperty as the backing store for ColorStart. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ColorLengthProperty =
DependencyProperty.RegisterAttached("ColorLength", typeof(int), typeof(ColoredLettering), new FrameworkPropertyMetadata(0, OnColorLengthChanged));
private static void OnColorLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = d as TextBlock;
if (textBlock != null)
{
if (e.NewValue == e.OldValue) return;
if (e.NewValue is int)
{
int start = GetColorStart(textBlock);
Brush brush = GetForeColor(textBlock);
if ((int)e.NewValue <= 0 || start <= 0 || brush == TextBlock.ForegroundProperty.DefaultMetadata.DefaultValue) return;
if (textBlock.TextEffects.Count != 0)
{
textBlock.TextEffects.Clear();
}
TextEffect textEffect = new TextEffect()
{
Foreground = brush,
PositionStart = start,
PositionCount = (int)e.NewValue
};
textBlock.TextEffects.Add(textEffect);
}
}
}
public static void SetForeColor(TextBlock textElement, Brush value)
{
textElement.SetValue(ColorStartProperty, value);
}
public static Brush GetForeColor(TextBlock textElement)
{
return (Brush)textElement.GetValue(ForeColorProperty);
}
// Using a DependencyProperty as the backing store for ForeColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ForeColorProperty =
DependencyProperty.RegisterAttached("ForeColor", typeof(Brush), typeof(ColoredLettering), new PropertyMetadata(TextBlock.ForegroundProperty.DefaultMetadata.DefaultValue, OnForeColorChanged));
private static void OnForeColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = d as TextBlock;
if (textBlock != null)
{
if (e.NewValue == e.OldValue) return;
if (e.NewValue is Brush)
{
int start = GetColorStart(textBlock);
int count = GetColorLength(textBlock);
if (start <= 0 || count <= 0) return;
if (textBlock.TextEffects.Count != 0)
{
textBlock.TextEffects.Clear();
}
TextEffect textEffect = new TextEffect()
{
Foreground = (Brush)e.NewValue,
PositionStart = start,
PositionCount = count
};
textBlock.TextEffects.Add(textEffect);
}
}
}
}
调用时只需在TextBlock指定需要高亮内容的开始位置,内容长度以及高亮颜色即可。
<TextBlock local:ColoredLettering.ColorLength="{Binding Count}"
local:ColoredLettering.ColorStart="{Binding Start}"
local:ColoredLettering.ForeColor="{Binding ForeColor}"
FontSize="20"
Text="Hello World" />
总结
本文介绍的方法只是高亮第一个匹配到的关键字,如果需要高亮匹配到的所有内容,只需要对附加属性进行改造,以支持传入一组位置和颜色信息。
最后分享一个可以解析一组有限的HTML标记并显示它们的WPF控件HtmlTextBlock,通过这个控件也可以实现查找结果中高亮关键字,甚至支持指定内容触发事件做一些逻辑操作。
WPF使用TextBlock实现查找结果高亮显示的更多相关文章
- WPF中TextBlock文本换行与行间距
原文:WPF中TextBlock文本换行与行间距 换行符: C#代码中:\r\n 或 \r 或 \n XAML中: 或 注:\r 回车 (carriage return 缩写),\n 新行 (new ...
- 用WPF实现查找结果高亮显示
概述 我们经常会遇到这样的需求:到数据库里查找一些关键字,把带这些关键字的记录返回显示在客户端上.但如果仅仅是单纯地把文本显示出来,那很不直观,用户不能很轻易地看到他们想找的内容,所以通常我们还要做到 ...
- WPF控件 RichTextBox查找定位匹配字符
private void Search_Click(object sender, RoutedEventArgs e)//查询定位文本 { List<TextRange> textRang ...
- WPF TextBox/TextBlock 文本超出显示时,文本靠右显示
文本框显示 文本框正常显示: 文本框超出区域显示: 实现方案 判断文本框是否超出区域 请见<TextBlock IsTextTrimmed 判断文本是否超出> 设置文本布局显示 1. Fl ...
- WPF 中 TextBlock 文本换行与行间距
换行符: C#代码中:\r\n 或 \r 或 \n XAML中: 或 注:\r 回车 (carriage return 缩写),\n 新行 (new line 缩写). 行间距: LineHeigh ...
- 【WPF】TextBlock文本文字分段显示不同颜色
需求:一行文字中,不同字符显示不同颜色.如注册页面,为表示必填项,在文本最后加一个红色的型号* 目标效果: 方法一: 用< StackPanel >嵌套两个< TextBlock & ...
- 【C#/WPF】TextBlock/TextBox/Label编辑文字的问题
标题有点描述不清,就当是为了方便自己用时易于搜索到. 总之需求是:显示用户信息(文字)时,允许用户编辑自己的信息. 效果图如下: 点击[编辑]按钮前: 点击[编辑]按钮后,允许编辑: 别吐槽为甚性别还 ...
- wpf 类似TextBlock外观的Button的样式
<Style x:Key="noborderbtnStyle" TargetType="{x:Type Button}"> <Setter P ...
- WPF中textBlock 变色功能
<Window.Resources> <Storyboard x:Key="OnLoaded" RepeatBehavior="Forever" ...
- 年度巨献-WPF项目开发过程中WPF小知识点汇总(原创+摘抄)
WPF中Style的使用 Styel在英文中解释为”样式“,在Web开发中,css为层叠样式表,自从.net3.0推出WPF以来,WPF也有样式一说,通过设置样式,使其WPF控件外观更加美化同时减少了 ...
随机推荐
- Jan 2023-Prioritizing Samples in Reinforcement Learning with Reducible Loss
1 Introduction 本文建议根据样本的可学习性进行抽样,而不是从经验回放中随机抽样.如果有可能减少代理对该样本的损失,则认为该样本是可学习的.我们将可以减少样本损失的数量称为其可减少损失(R ...
- springboot 多环境配置及配置文件的位置
了解即可
- Linux之从进程角度来理解文件描述符
文件描述符是一个非负整数,而内核需要通过这个文件描述符才可以访问文件.当我们在系统中打开已有的文件或新建文件时,内核每次都会给特定的进程返回一个文件描述符,当进程需要对文件进行读或写操作时,都要依赖这 ...
- jQuery 添加水印
jQuery 添加水印 <script src="../../../../AJs/jquery.min.js"></script> <script t ...
- 基于 Linux 集群环境上 GPFS 的问题诊断
作者:谷珊,帅炜,陈志阳来源:IBM Developer GPFS 的概述 GPFS 是 IBM 公司提供的一个共享文件系统,它允许所有的集群节点可以并行访问整个文件系统.GPFS 允许客户共享文件, ...
- 【Rust-book】第五章 使用结构体来组织相关联的数据
第五章 使用结构体来组织相关联的数据 结构,或者结构体,是一种自定义数据类型,它允许我们命名多个相关的值并将它们组成一个有机的结合体. 可以把结构体视作对象中的数据属性 1 对比元组和结构体之间的异同 ...
- 用CSS实现带动画效果的单选框
预览一下效果:http://39.105.101.122/myhtml/CSS/singlebox2/singleRadio.html 布局结构为: 1 <div class="rad ...
- .NETCore项目在Windows下构建Docker镜像并本地导出分发到CentOS系统下
在Windows下使用Docker,我们选择Docker Desktop这个软件,非常方便. Docker Desktop介绍及安装 Docker Desktop是适用于Mac.Linux或Windo ...
- CentOS 8搭建Docker镜像私有仓库-registry
目录 简介 安装Docker 添加docker yum源 安装docker 确保网络模块开机自动加载 使桥接流量对iptables可见 配置docker 验证docker是否正常 添加用户到docke ...
- Windows系统使用Nginx部署Vue
Nginx是什么? Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器 ,同时也提供了IMAP/POP3/SMTP服务.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的R ...