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控件外观更加美化同时减少了 ...
随机推荐
- 火山引擎DataTester:A/B实验平台数据集成技术分享
DataTester的数据集成系统,可大幅降低企业接入A/B实验平台门槛. 当企业想要接入一套A/B实验平台的时候,常常会遇到这样的问题: 企业已经有一套埋点系统了,增加A/B实验平台的话需要重复 ...
- IBM小型机 - AIX系统配置IP
AIX系统网口配置IP 前言 新部署的系统都是要通过IP来访问的,但是AIX系统配置IP的方式和Linux的不一样: 为了配置后可以通过远程访问系统,我们要给网口配置上IP. 操作步骤 1.新部署的A ...
- 【GiraKoo】Github无法打开,导致无法下载Git安装包
环境 Windows 11 原因 Git应用的安装程序在Github上,由于Github访问不稳定,导致无法下载. 对策 打开迅雷.将下载链接拷贝进去,利用迅雷的P2P技术,从其他网友处进行下载. 打 ...
- linux中使用jenkins自动部署前端工程
1.去年在自己的服务器上安装了jenkins,说用来自己研究一下jenkins自动化部署前端项目,jenkins安装好了,可是一直没管,最近终于研究了一下使用jenkins自动化部署,以此记录下来. ...
- ubuntu配置vscode全过程(下载安装配置优化插件)
一.安装vscode 下载vscode 当然啦,我们安装vscode,当然要先下载啦,但是但是但是!不要在ubuntu的软件中心(Ubuntu Software)下载!贼坑!下载完不能用! 推荐下载方 ...
- 计算机网络 VRRP和DHCP
目录 一.vrrp概念 二.vrrp工作过程 三.vrrp优先级 四.vrrp实验 五.DHCP概念 六.DHCP工作过程 七.DHCP实验 一.vrrp概念 概念:称虚拟路由器冗余协议,当网关路由器 ...
- 代码随想录算法训练营Day39 动态规划
代码随想录算法训练营 代码随想录算法训练营Day38 动态规划|62.不同路径 63. 不同路径 II 62.不同路径 题目链接:62.不同路径 一个机器人位于一个 m x n 网格的左上角 (起始点 ...
- < Python全景系列-9 > Python 装饰器:优雅地增强你的函数和类
欢迎来到我们的系列博客<Python全景系列>第九篇!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法.无论你是编程新手,还 ...
- 高分辨率大图像可缩放 Web 查看器的实践
高分辨率大图像可缩放 Web 查看器的实践 一.使用 vips 将高分辨率大图像转换为 DZI 安装 vips 具体安装步骤请参考libvips Install. 注意,在 windows 11 中安 ...
- ESP8266-01S烧录固件
ESP8266-01S 整理了一下ESP01S的烧录固件和烧录APP 链接:https://pan.baidu.com/s/1DApOQcWhqvk378ZklJSypA 提取码:1028 文件夹包含 ...