WPF RichTextBox将插入符号放置到具有给定索引

时间:2016-03-06 12:07:53

标签: c# wpf richtextbox

我一直在寻找WPF中的快速方法,以编程方式将光标设置为指定的可见符号索引。

问题在于,仅使用Document.ContentStart.GetPositionAtOffset(cursorIndex, LogicalDirection.Forward)我没有得到所需的结果,因为此方法也会计算不可见的符号 - 例如Run start和Run结束符号。文档中几乎总有一些demarkation符号,所以这总是以光标位于所需位置之前结束。

那么,只考虑可见符号,将插入符号放置到指定索引的快速,简单和优雅的方法是什么?

1 个答案:

答案 0 :(得分:1)

我提出了以下解决方案:

public virtual void SetCursorIndex(Int32 cursorIndex)
{
    // If the specified index is less than or equal to 0, then we simply
    // position the caret to the start of the document.
    if (cursorIndex <= 0)
    {
        CaretPosition = Document.ContentStart;
        return;
    }

    // If the specified index is greater than or equal to the total length, we simply
    // position the caret to the end of the document.
    String fullText = new TextRange(Document.ContentStart, Document.ContentEnd).Text;
    Int32 totalTextLength = fullText.Length;
    if (cursorIndex >= totalTextLength)
    {
        CaretPosition = Document.ContentEnd;
        return;
    }

    // (*)
    TextPointer endPtr = Document.ContentStart
        .GetPositionAtOffset(cursorIndex, LogicalDirection.Forward);
    TextRange range = new TextRange(Document.ContentStart, endPtr);
    Int32 diff = cursorIndex - range.Text.Length;
    while (diff != 0)
    {
        endPtr = endPtr.GetPositionAtOffset(diff, LogicalDirection.Forward);
        range = new TextRange(Document.ContentStart, endPtr);
        diff = cursorIndex - range.Text.Length;

        // Overindexing, in this case we went over the document's length so we
        // position the caret to the end of the document as a safety measure.
        if (diff < 0)
        {
            endPtr = Document.ContentEnd;
            break;
        }
    }

    CaretPosition = endPtr;
}

// (*)之前的部分是不言自明的。从那里,我们执行以下操作:

  • 我们使用内置机制在cursorIndex逻辑位置(相对于文档的开头)获取文本指针 - 再次,这包括不可见的符号。但如果确实如此,我们就不能超过所需的可见字符索引,只能在它之前。如果它不包含任何不可见的符号,则此方法会为我们提供一个TextPointer,它位于我们想要的位置。
  • 我们创建一个TextRange对象,该对象受文档开头和之前创建的TextPointer的限制。
  • 我们计算cursorIndex对象中文本的LengthTextRange的差异。这是我们迭代地推进指针直到差值为0的量。这是一种简单的启发式方法,比迭代推进它的速度快一点。它基于如果TextRange的事实对象包含任何不可见的符号,那么可见符号的数量永远不会超过我们必须推进endPtr TextPointer的位置数量,所以我们这样做 - 我们推进endPtr cursorIndexrange.Length的差异。如果期望的位置与endPtr指向的当前位置之间存在任何不可见的符号,那么我们仍然无法完全达到所需的位置 - 这就是我们为{{1}推进的原因在endPtr - 循环测试中,whilerange包含的文本长度差为0。