WPF .NET Core中SelectionTextBrush失效,求高亮文本变色解决方案
.NET Core 7下WPF RichTextBox选中文本变色的替代方案
由于.NET Core 7中WPF的RichTextBox无法通过原有.NET Framework的样式方案修改选中文本颜色,这里提供一种基于事件监听和FlowDocument文本元素操作的替代实现。
核心思路
通过监听SelectionChanged事件,手动遍历选中范围内的文本元素,修改其前景色;同时记录元素的原始颜色,在取消选中时恢复样式。针对部分选中单个Run的场景,还可以拆分Run实现精确的片段变色。
基础实现(全Run选中变色)
XAML代码
<RichTextBox x:Name="MyRichTextBox" SelectionChanged="MyRichTextBox_SelectionChanged" Background="#2D2D2D"> <FlowDocument> <Paragraph Foreground="#E0E0E0"> 测试文本:选中这段文字查看颜色变化,切换选中范围会自动恢复原始样式。 </Paragraph> </FlowDocument> </RichTextBox>
后台代码
using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; namespace WpfApp { public partial class MainWindow : Window { // 记录被修改的Run及其原始前景色 private readonly Dictionary<Run, Brush> _originalBrushes = new Dictionary<Run, Brush>(); public MainWindow() { InitializeComponent(); } private void MyRichTextBox_SelectionChanged(object sender, RoutedEventArgs e) { var rtb = sender as RichTextBox; if (rtb == null) return; // 恢复之前选中元素的原始颜色 foreach (var item in _originalBrushes) { item.Key.Foreground = item.Value; } _originalBrushes.Clear(); if (rtb.Selection.IsEmpty) return; var start = rtb.Selection.Start; var end = rtb.Selection.End; // 遍历选中区域内的所有Run元素 while (start.CompareTo(end) <= 0) { if (start.Parent is Run run) { if (!_originalBrushes.ContainsKey(run)) { _originalBrushes[run] = run.Foreground; } // 设置选中文本的颜色,这里用白色示例 run.Foreground = Brushes.White; } // 移动到下一个文本节点 if (!start.MoveToNextContextPosition(LogicalDirection.Forward)) { break; } } } } }
进阶实现(支持部分Run选中变色)
如果需要精确到选中的文本片段(而非整个Run),可以拆分Run元素,仅修改选中的部分:
补充后台代码
private void MyRichTextBox_SelectionChanged(object sender, RoutedEventArgs e) { var rtb = sender as RichTextBox; if (rtb == null) return; // 恢复之前选中元素的原始颜色 foreach (var item in _originalBrushes) { item.Key.Foreground = item.Value; } // 合并相邻同样式的Run,避免过多元素影响性能 MergeAdjacentRuns(rtb.Document); _originalBrushes.Clear(); if (rtb.Selection.IsEmpty) return; ProcessSelectionRange(rtb.Selection.Start, rtb.Selection.End); } // 处理选中范围的文本元素 private void ProcessSelectionRange(TextPointer start, TextPointer end) { while (start.CompareTo(end) < 0) { if (start.Parent is Run run) { var runStart = run.ContentStart; var runEnd = run.ContentEnd; // 场景1:Run完全在选中范围内 if (runStart.CompareTo(start) >= 0 && runEnd.CompareTo(end) <= 0) { RecordAndChangeRunColor(run); start = runEnd; } // 场景2:Run的后半部分被选中 else if (runStart.CompareTo(start) < 0 && runEnd.CompareTo(start) > 0 && runEnd.CompareTo(end) <= 0) { var splitRun = run.Split(start); RecordAndChangeRunColor(splitRun); start = runEnd; } // 场景3:Run的前半部分被选中 else if (runStart.CompareTo(start) >= 0 && runStart.CompareTo(end) < 0 && runEnd.CompareTo(end) > 0) { var splitRun = run.Split(end); RecordAndChangeRunColor(run); start = end; } // 场景4:Run的中间部分被选中 else if (runStart.CompareTo(start) < 0 && runEnd.CompareTo(end) > 0) { var middleRun = run.Split(start); middleRun.Split(end); RecordAndChangeRunColor(middleRun); start = end; } else { start = runEnd; } } else { if (!start.MoveToNextContextPosition(LogicalDirection.Forward)) { break; } } } } // 记录Run原始颜色并修改选中颜色 private void RecordAndChangeRunColor(Run run) { if (!_originalBrushes.ContainsKey(run)) { _originalBrushes[run] = run.Foreground; } run.Foreground = Brushes.White; } // 合并相邻同样式的Run,优化文档性能 private void MergeAdjacentRuns(FlowDocument doc) { foreach (var para in doc.Blocks.OfType<Paragraph>()) { var runs = para.Inlines.OfType<Run>().ToList(); for (int i = runs.Count - 1; i > 0; i--) { var current = runs[i]; var previous = runs[i - 1]; // 判断样式是否一致(可根据需求添加更多样式判断) if (current.Foreground == previous.Foreground && current.FontFamily == previous.FontFamily && current.FontSize == previous.FontSize && current.FontStyle == previous.FontStyle && current.FontWeight == previous.FontWeight) { previous.Text += current.Text; para.Inlines.Remove(current); } } } }
方案说明
- 该实现完全基于WPF原生API,兼容.NET Core 7及更高版本。
- 基础实现适合对选中精度要求不高的场景,代码简洁;进阶实现支持精确到文本片段的变色,但逻辑稍复杂。
- 通过合并相邻Run的操作,可以避免频繁拆分导致文档元素过多,优化性能。
内容的提问来源于stack exchange,提问作者user21301374
相关产品推荐
相关产品推荐

