4
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 来更改所选文本的背景颜色时,它在第一次时效果很好,但在第二次调用时它不能正确调整所选文本段的背景颜色。我怀疑这与调用函数后文档的偏移量以某种方式被搞砸有关。

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

4

3 回答 3

7

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

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);
于 2012-08-27T12:11:48.273 回答
1

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

这个解决方案的问题是速度非常慢。例如,使用此方法选择大约 150 条文本的应用程序需要大约 20 秒来执行,而其中的大约 20 毫秒都用于选择文本!

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

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

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

于 2013-03-10T13:42:09.420 回答
0

感谢 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--;
于 2015-04-28T11:27:58.733 回答