UWP中RichTextBlock文本高亮保留格式的实现咨询
Your current approach loses formatting because you're splitting the original text and creating new Run elements from scratch, which don't carry over the original font styles, colors, etc. The correct way to handle this without modifying the original content is using TextHighlighter—it's designed specifically to highlight text ranges while preserving existing formatting.
Here's how to implement it step by step:
Step 1: Understand TextHighlighter Basics
TextHighlighter lets you define one or more TextRange objects (each representing a start index and length of text to highlight) and applies a brush to those ranges. It works directly with your existing content, so there's no need to split or rebuild your RichTextBlock's inlines.
Step 2: Implement the Highlighting Logic
Replace your existing btnFind_Click method with the following code. This will:
- Collect all text and track each
Run's position in the combined text - Find all occurrences of the search term
- Map each occurrence back to the original text ranges
- Apply the highlight using
TextHighlighter
private void btnFind_Click(object sender, RoutedEventArgs e) { string searchTerm = txbToFind.Text.Trim(); if (string.IsNullOrEmpty(searchTerm)) { // Clear existing highlights if search term is empty RichTextBlockText.TextHighlighters.Clear(); return; } // Step 1: Collect all text and track each Run's start/end indices List<RunInfo> runInfos = new List<RunInfo>(); int currentPosition = 0; foreach (Run run in Testo.Inlines.OfType<Run>()) { int length = run.Text.Length; runInfos.Add(new RunInfo { Run = run, StartIndex = currentPosition, EndIndex = currentPosition + length }); currentPosition += length; } string fullText = string.Concat(runInfos.Select(r => r.Run.Text)); List<TextRange> highlightRanges = new List<TextRange>(); // Step 2: Find all occurrences of the search term int searchIndex = fullText.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase); while (searchIndex != -1) { int termLength = searchTerm.Length; int termEndIndex = searchIndex + termLength; // Step 3: Map the occurrence to the relevant Runs and create TextRanges foreach (var runInfo in runInfos) { // Check if this Run overlaps with the current search term if (runInfo.EndIndex > searchIndex && runInfo.StartIndex < termEndIndex) { int rangeStart = Math.Max(searchIndex, runInfo.StartIndex) - runInfo.StartIndex; int rangeLength = Math.Min(termEndIndex, runInfo.EndIndex) - Math.Max(searchIndex, runInfo.StartIndex); highlightRanges.Add(new TextRange { StartIndex = runInfo.StartIndex + rangeStart, Length = rangeLength }); } } // Find next occurrence searchIndex = fullText.IndexOf(searchTerm, searchIndex + termLength, StringComparison.OrdinalIgnoreCase); } // Step 4: Apply the highlights RichTextBlockText.TextHighlighters.Clear(); if (highlightRanges.Any()) { TextHighlighter highlighter = new TextHighlighter(); highlighter.Background = new SolidColorBrush(Colors.Yellow); highlighter.Ranges.AddRange(highlightRanges); RichTextBlockText.TextHighlighters.Add(highlighter); } } // Helper class to track Run positions private class RunInfo { public Run Run { get; set; } public int StartIndex { get; set; } public int EndIndex { get; set; } }
Step 3: Clean Up Old Code
You can delete the MakeHighlightedParagraph method entirely—TextHighlighter handles all highlight styling directly without needing to create new inline elements.
How This Works
- Preserves Original Formatting: We never modify the original
Runelements. TheTextHighlightersimply overlays a background color on the specified text ranges, leaving original font styles, colors, and sizes intact. - Handles Cross-Run Highlights: If your search term spans multiple
Runelements (e.g., part in the italic run and part in the bold run), the code correctly splits the highlight into relevant ranges across those Runs. - Flexible Search: The example uses case-insensitive search—you can change
StringComparison.OrdinalIgnoreCasetoOrdinalif you want case-sensitive matching.
Additional Notes
TextHighlightersupports advanced brush types likeLinearGradientBrushif you want custom highlight styles.- To highlight multiple terms with different colors, create separate
TextHighlighterobjects (each with its own brush and ranges) and add all to theTextHighlighterscollection.
内容的提问来源于stack exchange,提问作者LightGreen

