如何在RichTextBox中的文本上正确应用backgroundcolor

internal string Select(RichTextBox rtb, int index, int length) { TextRange textRange = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd); if (textRange.Text.Length >= (index + length)) { TextPointer start = textRange.Start.GetPositionAtOffset(index, LogicalDirection.Forward); TextPointer end = textRange.Start.GetPositionAtOffset(index + length, LogicalDirection.Backward); rtb.Selection.Select(start, end); rtb.Selection.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.LightBlue)); } return rtb.Selection.Text; } 

每当调用ApplyPropertyValue来更改所选文本的背景颜色时,它首次运行良好,但在第二次调用时不能正确调整所选文本段的背景颜色。 我怀疑这与调用函数后文件的偏移量有些混乱有关。

解决这个问题的好方法是什么?

试试这个(它需要一个比你更复杂的逻辑),否则是:你有偏移问题!

 private static TextPointer GetTextPointAt(TextPointer from, int pos) { TextPointer ret = from; int i = 0; while ((i < pos) && (ret != null)) { if ((ret.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text) || (ret.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.None)) i++; if (ret.GetPositionAtOffset(1, LogicalDirection.Forward) == null) return ret; ret = ret.GetPositionAtOffset(1, LogicalDirection.Forward); } return ret; } internal string Select(RichTextBox rtb, int offset, int length, Color color) { // Get text selection: TextSelection textRange = rtb.Selection; // Get text starting point: TextPointer start = rtb.Document.ContentStart; // Get begin and end requested: TextPointer startPos = GetTextPointAt(start, offset); TextPointer endPos = GetTextPointAt(start, offset + length); // New selection of text: textRange.Select(startPos, endPos); // Apply property to the selection: textRange.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(color)); // Return selection text: return rtb.Selection.Text; } 

然后以这种方式使用它(我选择从第一个字符到第五个字符在RED中):

 this.Select(this.myRichTextBox, 0, 5, Colors.Red); 

首先,MAXE给出了很好的答案,因为它清楚地向我展示了我遇到的根本问题:需要记住WPF中的流文档控件正在处理标记,而不是原始文本。 因此,潜在的问题是跳过标记,直到您实际处理包含元素内的文本。

这个解决方案的问题在于它非常慢。 例如,一个选择大约150个文本的应用程序需要大约20秒才能使用这种方法执行,除了大约20ms的文本用于选择文本!

这个问题没有通用的解决方案可以在所有情况下使用,但仔细考虑您要实现的目标并进行相应优化是值得的。 常见的情况是创建单个运行(段落等)并在其中放置一个文本块,然后在该单个元素中选择/突出显示文本。 在这种情况下,您知道只有一个’元素’,因此您可以执行以下操作,这将获得与上面相同的结果:

  internal static TextPointer GetOffsetTextPointer(this TextPointer start, int offset) { return start.GetInsertionPosition(LogicalDirection.Forward).GetPositionAtOffset(offset); } 

作为参考, GetInsertionPosition方法将跳过起始元素标记,直到文本实际开始的位置,然后GetPositionAtOffset方法在一次调用中获取实际指针。 为了进行比较,上面的示例现在执行时间不到2秒。

感谢MAXE这个出色的解决方案。

在rtf文本中使用换行符和其他不可见字符可能会遇到麻烦。 要解决此问题,请在方法的开头添加偏移校正器:

 // Get the text between start and offset string rtfBoxContentToOffset = rtfBoxContent.Substring(0, offset); // check for linebreaks or other and decrement the offset foreach (char character in rtfBoxContentToOffset) if (character == '\r' || character == '\n') offset--;