在应用开发过程中,经常遇到这样的需求:通过关键字查找数据,把带有关键字的数据显示出来,同时在结果中高亮显示关键字。在web开发中,只需在关键字上加一层标签,然后设置标签样式就可以轻松实现。

在WPF中显示文本内容通常采用TextBlock控件,也可以采用类似的方式,通过内联流内容元素Run达到同样的效果:

  1. <TextBlock FontSize="20">
  2. <Run Text="Hel" /><Run Foreground="Red" Text="lo " /><Run Text="Word" />
  3. </TextBlock>

需要注意的是每个Run之间不要换行,如果换行的话,每个Run之间会有间隙,看起来像增加了空格。

通过这种方式实现查找结果中高亮关键字,需要把查找结果拆分成三部分,然后绑定到Run元素的Text属性,或者在后台代码中使用TextBlockInlines属性添加Run元素

  1. textBlock1.Inlines.Add(new Run("hel"));
  2. textBlock1.Inlines.Add(new Run("lo ") { Foreground=new SolidColorBrush(Colors.Red)});
  3. textBlock1.Inlines.Add(new Run("world"));

这种方法虽然可以达到效果,但显然与MVVM的思想不符。接下来本文介绍一种通过附加属性实现TextBlock中指定内容高亮。

技术要点与实现

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

  • 首先定义类ColoredLettering(并不要求继承DependencyObject)。
  • ColoredLettering中注册自定义的附加属性,注册附加属性方式与注册依赖属性类似,不过附加属性是用DependencyProperty.RegisterAttached来注册。
  • 给附加属性注册属性值变化事件,事件处理逻辑中设置TextEffectPositionStartPositionCount以及Foreground实现内容高亮。
  1. public class ColoredLettering
  2. {
  3. public static void SetColorStart(TextBlock textElement, int value)
  4. {
  5. textElement.SetValue(ColorStartProperty, value);
  6. }
  7. public static int GetColorStart(TextBlock textElement)
  8. {
  9. return (int)textElement.GetValue(ColorStartProperty);
  10. }
  11. // Using a DependencyProperty as the backing store for ColorStart. This enables animation, styling, binding, etc...
  12. public static readonly DependencyProperty ColorStartProperty =
  13. DependencyProperty.RegisterAttached("ColorStart", typeof(int), typeof(ColoredLettering), new FrameworkPropertyMetadata(0, OnColorStartChanged));
  14. private static void OnColorStartChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  15. {
  16. TextBlock textBlock = d as TextBlock;
  17. if (textBlock != null)
  18. {
  19. if (e.NewValue == e.OldValue) return;
  20. if (e.NewValue is int)
  21. {
  22. int count = GetColorLength(textBlock);
  23. Brush brush = GetForeColor(textBlock);
  24. if ((int)e.NewValue <= 0 || count <= 0 || brush == TextBlock.ForegroundProperty.DefaultMetadata.DefaultValue) return;
  25. if (textBlock.TextEffects.Count != 0)
  26. {
  27. textBlock.TextEffects.Clear();
  28. }
  29. TextEffect textEffect = new TextEffect()
  30. {
  31. Foreground = brush,
  32. PositionStart = (int)e.NewValue,
  33. PositionCount = count
  34. };
  35. textBlock.TextEffects.Add(textEffect);
  36. }
  37. }
  38. }
  39. public static void SetColorLength(TextBlock textElement, int value)
  40. {
  41. textElement.SetValue(ColorLengthProperty, value);
  42. }
  43. public static int GetColorLength(TextBlock textElement)
  44. {
  45. return (int)textElement.GetValue(ColorLengthProperty);
  46. }
  47. // Using a DependencyProperty as the backing store for ColorStart. This enables animation, styling, binding, etc...
  48. public static readonly DependencyProperty ColorLengthProperty =
  49. DependencyProperty.RegisterAttached("ColorLength", typeof(int), typeof(ColoredLettering), new FrameworkPropertyMetadata(0, OnColorLengthChanged));
  50. private static void OnColorLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  51. {
  52. TextBlock textBlock = d as TextBlock;
  53. if (textBlock != null)
  54. {
  55. if (e.NewValue == e.OldValue) return;
  56. if (e.NewValue is int)
  57. {
  58. int start = GetColorStart(textBlock);
  59. Brush brush = GetForeColor(textBlock);
  60. if ((int)e.NewValue <= 0 || start <= 0 || brush == TextBlock.ForegroundProperty.DefaultMetadata.DefaultValue) return;
  61. if (textBlock.TextEffects.Count != 0)
  62. {
  63. textBlock.TextEffects.Clear();
  64. }
  65. TextEffect textEffect = new TextEffect()
  66. {
  67. Foreground = brush,
  68. PositionStart = start,
  69. PositionCount = (int)e.NewValue
  70. };
  71. textBlock.TextEffects.Add(textEffect);
  72. }
  73. }
  74. }
  75. public static void SetForeColor(TextBlock textElement, Brush value)
  76. {
  77. textElement.SetValue(ColorStartProperty, value);
  78. }
  79. public static Brush GetForeColor(TextBlock textElement)
  80. {
  81. return (Brush)textElement.GetValue(ForeColorProperty);
  82. }
  83. // Using a DependencyProperty as the backing store for ForeColor. This enables animation, styling, binding, etc...
  84. public static readonly DependencyProperty ForeColorProperty =
  85. DependencyProperty.RegisterAttached("ForeColor", typeof(Brush), typeof(ColoredLettering), new PropertyMetadata(TextBlock.ForegroundProperty.DefaultMetadata.DefaultValue, OnForeColorChanged));
  86. private static void OnForeColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  87. {
  88. TextBlock textBlock = d as TextBlock;
  89. if (textBlock != null)
  90. {
  91. if (e.NewValue == e.OldValue) return;
  92. if (e.NewValue is Brush)
  93. {
  94. int start = GetColorStart(textBlock);
  95. int count = GetColorLength(textBlock);
  96. if (start <= 0 || count <= 0) return;
  97. if (textBlock.TextEffects.Count != 0)
  98. {
  99. textBlock.TextEffects.Clear();
  100. }
  101. TextEffect textEffect = new TextEffect()
  102. {
  103. Foreground = (Brush)e.NewValue,
  104. PositionStart = start,
  105. PositionCount = count
  106. };
  107. textBlock.TextEffects.Add(textEffect);
  108. }
  109. }
  110. }
  111. }

调用时只需在TextBlock指定需要高亮内容的开始位置,内容长度以及高亮颜色即可。

  1. <TextBlock local:ColoredLettering.ColorLength="{Binding Count}"
  2. local:ColoredLettering.ColorStart="{Binding Start}"
  3. local:ColoredLettering.ForeColor="{Binding ForeColor}"
  4. FontSize="20"
  5. Text="Hello World" />

总结

本文介绍的方法只是高亮第一个匹配到的关键字,如果需要高亮匹配到的所有内容,只需要对附加属性进行改造,以支持传入一组位置和颜色信息。

最后分享一个可以解析一组有限的HTML标记并显示它们的WPF控件HtmlTextBlock,通过这个控件也可以实现查找结果中高亮关键字,甚至支持指定内容触发事件做一些逻辑操作。

WPF使用TextBlock实现查找结果高亮显示的更多相关文章

  1. WPF中TextBlock文本换行与行间距

    原文:WPF中TextBlock文本换行与行间距 换行符: C#代码中:\r\n 或  \r 或 \n XAML中: 或 注:\r 回车 (carriage return 缩写),\n 新行 (new ...

  2. 用WPF实现查找结果高亮显示

    概述 我们经常会遇到这样的需求:到数据库里查找一些关键字,把带这些关键字的记录返回显示在客户端上.但如果仅仅是单纯地把文本显示出来,那很不直观,用户不能很轻易地看到他们想找的内容,所以通常我们还要做到 ...

  3. WPF控件 RichTextBox查找定位匹配字符

    private void Search_Click(object sender, RoutedEventArgs e)//查询定位文本 { List<TextRange> textRang ...

  4. WPF TextBox/TextBlock 文本超出显示时,文本靠右显示

    文本框显示 文本框正常显示: 文本框超出区域显示: 实现方案 判断文本框是否超出区域 请见<TextBlock IsTextTrimmed 判断文本是否超出> 设置文本布局显示 1. Fl ...

  5. WPF 中 TextBlock 文本换行与行间距

    换行符: C#代码中:\r\n 或  \r 或 \n XAML中: 或 注:\r 回车 (carriage return 缩写),\n 新行 (new line 缩写). 行间距: LineHeigh ...

  6. 【WPF】TextBlock文本文字分段显示不同颜色

    需求:一行文字中,不同字符显示不同颜色.如注册页面,为表示必填项,在文本最后加一个红色的型号* 目标效果: 方法一: 用< StackPanel >嵌套两个< TextBlock & ...

  7. 【C#/WPF】TextBlock/TextBox/Label编辑文字的问题

    标题有点描述不清,就当是为了方便自己用时易于搜索到. 总之需求是:显示用户信息(文字)时,允许用户编辑自己的信息. 效果图如下: 点击[编辑]按钮前: 点击[编辑]按钮后,允许编辑: 别吐槽为甚性别还 ...

  8. wpf 类似TextBlock外观的Button的样式

    <Style x:Key="noborderbtnStyle" TargetType="{x:Type Button}"> <Setter P ...

  9. WPF中textBlock 变色功能

    <Window.Resources> <Storyboard x:Key="OnLoaded" RepeatBehavior="Forever" ...

  10. 年度巨献-WPF项目开发过程中WPF小知识点汇总(原创+摘抄)

    WPF中Style的使用 Styel在英文中解释为”样式“,在Web开发中,css为层叠样式表,自从.net3.0推出WPF以来,WPF也有样式一说,通过设置样式,使其WPF控件外观更加美化同时减少了 ...

随机推荐

  1. vue全家桶进阶之路43:Vue3 Element Plus el-form表单组件

    在 Element Plus 中,el-form 是一个表单组件,用于创建表单以便用户填写和提交数据.它提供了许多内置的验证规则和验证方法,使表单验证更加容易. 使用 el-form 组件,您可以将表 ...

  2. .Net8顶级技术:边界检查之IR解析(慎入)

    前言 C#这种语言之所以号称安全的,面向对象的语言.这个安全两个字可不是瞎叫的哦.因为JIT会检查任何可能超出分配范围的数值,以便使其保持在安全边界内.这里有两个概念,其一边界检查,其二IR解析.后者 ...

  3. 在DevExpress中使用BandedGridView表格实现多行表头的处理

    在之前较早随笔中介绍过实现多行表头的处理,通过手工创建字段以及映射数据源字段属性的方式实现,有些客户反映是否可以通过代码方式更方便的创建对应的处理操作,因此本篇随笔继续探讨这个多行表头的处理的操作,使 ...

  4. AcWing 3956. 截断数组

    给定一个长度为 n 的数组 a1,a2,-,an. 现在,要将该数组从中间截断,得到三个非空子数组. 要求,三个子数组内各元素之和都相等. 请问,共有多少种不同的截断方法? 输入格式 第一行包含整数 ...

  5. Cesium开发案例整理

    weigis近几年越来越被人们所关注,但是二三维开发难度也比普通web要高出许多,不管我们是在在开发或者是学习过程中,往往需要耗费大量的时间去查阅资料,和研究官方案例, 而大多二三维的包(openla ...

  6. SpringBoot打包成WAR包的时候把第三方jar包打到LIB文件夹下和把第三方jar包打入到SpringBoot jar包中

    SpringBoot打包成WAR包的时候把第三方jar包打到LIB文件夹下和把第三方jar包打入到SpringBoot jar包中 转载 首先我们应该知道我们把SPRINGBOOT项目打包成WAR包和 ...

  7. vim 之中 U 命令的浅析

    以下文章来源于CSDN,作者黑翼天使56,本文章经原作者同意后授权转载. 今天看 vim帮助文档的 user-manual 的第二章,发现了还有U(大写)这个命令,于是反复实验,略微搞懂了一点它的用处 ...

  8. THM武器化

    Weaponization thm:https://tryhackme.com/room/weaponization 武器化 了解和探索常见的红队武器化技术.您将学习使用业内常见的方法构建自定义有效载 ...

  9. CF1817C Similar Polynomials

    简要题意 给定两个次数为 \(d\) 的多项式 \(A, B\) 在 \(0, 1, 2, \dots, d\) 处的点值对 \(10^9+7\) 取模,保证 \(B(x) \equiv A(x+s) ...

  10. 【python基础】文件-初识文件

    文本文件可存储的数据量是非常多的.每当需要分析或修改存储在文件中的信息时,首先就是读取文件到内存中,为此可以一次性读取文件的全部内容,也可以以每次一行的方式逐步读取. 1.读取文件 1.1读取整个文件 ...