WPF类Windows11搜索文件关键字高亮色块实现
WPF的TextBlock推荐高亮无非就是变几个字的颜色(没错就是这样),用TextBlock + Run实现
<TextBlock>
<!-- 普通文本 -->
<Run Text="这是一段需要部分"/>
<!-- 高亮文本 -->
<Run Text="高亮显示" Foreground="Red" FontWeight="Bold"/>
<!-- 继续普通文本 -->
<Run Text="的示例文本"/>
</TextBlock>
但是在一些业务环境中,这种方式不被用户接受
1.文字花花绿绿,可能有视觉疲劳
2.不高大上,UI显示不符合当下潮流
这时候,目光 就情不自禁的放到了Windows上
虽然Win11经常被诟病,但是UI样式还是很前卫的

在网上找了一圈,没有合适的实现,现在就分享一下自己写的破东西
<Rectangle Margin="{Binding HighlightLeftMargin,UpdateSourceTrigger=PropertyChanged}"
Width="{Binding HighlightWidth,UpdateSourceTrigger=PropertyChanged}"
Height="42" Fill="Yellow" VerticalAlignment="Center" HorizontalAlignment="Left"
RadiusX="12" RadiusY="12"/>
<TextBlock Foreground="Black" Text="The quick brown fox jumps over the lazy dog."
TextAlignment="Center" Loaded="TextBlock_Loaded" MaxWidth="520" FontSize="32"/>
XAML这样就有一个雏形了,核心思想就是在TextBlock下面放一个色块,动态调整色块来完成高亮
后台绑定数据:
private string _highlightword;
/// <summary>
/// 文件高亮词
/// </summary>
public string Highlightword
{
get
{
return _highlightword;
}
set
{
_highlightword = value;
RaisePropertyChanged();
}
}
private Thickness _highlightLeftMargin;
/// <summary>
/// 文件高亮词距离左边距离
/// </summary>
public Thickness HighlightLeftMargin
{
get
{
return _highlightLeftMargin;
}
set
{
_highlightLeftMargin = value;
RaisePropertyChanged();
}
}
private double _highlightWidth;
/// <summary>
/// 文件高亮词宽度
/// </summary>
public double HighlightWidth
{
get
{
return _highlightWidth;
}
set
{
_highlightWidth = value;
RaisePropertyChanged();
}
}
这样基础就来搭好了,只需要小小计算一下就可以了
首先在文本加载完成的时候加入Loaded事件:
private void TextBlock_Loaded(object sender, RoutedEventArgs e)
{
TextBlock textBlock = (TextBlock)sender;
var fileDataContext = textBlock.DataContext as 你自己储存的数据类型;
SetHighlightLocation(textBlock, 你自己储存的数据类型.Highlightword);
}
然后核心的方法就是这个 SetHighlightLocation 方法:
/// <summary>
/// 设置文本高光位置
/// </summary>
/// <param name="textBlock">文本控件</param>
/// <param name="keyword">关键词</param>
/// <returns></returns>
private void SetHighlightLocation(TextBlock textBlock, string keyword)
{
string fullText = textBlock.Text;
//没有关键词就别走下面了,渲染浪费性能
if (String.IsNullOrEmpty(keyword)) return;
//获得关键词在文本中的位置
int index = fullText.IndexOf(keyword, StringComparison.Ordinal);
if (index == -1) return;
// 创建临时TextBlock测量高亮块距离左边像素宽度
var tempTextBlock = new TextBlock
{
Text = fullText[..index],
FontFamily = textBlock.FontFamily,
FontSize = textBlock.FontSize,
FontWeight = textBlock.FontWeight,
FontStyle = textBlock.FontStyle
};
// 创建临时TextBlock测量高亮块宽度
var tempTextBlock2 = new TextBlock
{
//这个就是Idex加上关键字的长度,就是高亮色块最右边位置
Text = fullText[..(index + keyword.Length)],
FontFamily = textBlock.FontFamily,
FontSize = textBlock.FontSize,
FontWeight = textBlock.FontWeight,
FontStyle = textBlock.FontStyle
};
//确保两个临时文本块都被计算和渲染
tempTextBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
tempTextBlock.Arrange(new Rect(tempTextBlock.DesiredSize));
tempTextBlock2.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
tempTextBlock2.Arrange(new Rect(tempTextBlock2.DesiredSize));
//用高亮块距离左边像素宽度长度(tempTextBlock.ActualWidth)+最大控件长度减去文本宽度的一半(即左右两边的空白像素宽度)
var thickness = new Thickness((int)tempTextBlock.ActualWidth + ((textBlock.ActualWidth - textBlock.DesiredSize.Width) / 2), 0, 0, 0);
//色块最右边位置减掉最左边位置就是色块长度
var width = tempTextBlock2.ActualWidth - tempTextBlock.ActualWidth;
((你自己储存的数据类型)(textBlock.DataContext)).HighlightLeftMargin = thickness;
((你自己储存的数据类型)(textBlock.DataContext)).HighlightWidth = width;
*这里的 ((textBlock.MaxWidth - textBlock.ActualWidth) / 2) 主要为了处理文本是居中显示,那么没有到达最大文本宽度之前,左右都会有空白,不一定需要
这里用本机文件下的音乐测试,KeyWord为.mp3:

效果拔群!

浙公网安备 33010602011771号