我一直在寻找WPF中的快速方法,以编程方式将光标设置为指定的可见符号索引。
问题在于,仅使用Document.ContentStart.GetPositionAtOffset(cursorIndex, LogicalDirection.Forward)
我没有得到所需的结果,因为此方法也会计算不可见的符号 - 例如Run
start和Run
结束符号。文档中几乎总有一些demarkation符号,所以这总是以光标位于所需位置之前结束。
那么,只考虑可见符号,将插入符号放置到指定索引的快速,简单和优雅的方法是什么?
答案 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
对象中文本的Length
和TextRange
的差异。这是我们迭代地推进指针直到差值为0的量。这是一种简单的启发式方法,比迭代推进它的速度快一点。它基于如果TextRange
的事实对象包含任何不可见的符号,那么可见符号的数量永远不会超过我们必须推进endPtr
TextPointer
的位置数量,所以我们这样做 - 我们推进endPtr
cursorIndex
和range.Length
的差异。如果期望的位置与endPtr
指向的当前位置之间存在任何不可见的符号,那么我们仍然无法完全达到所需的位置 - 这就是我们为{{1}推进的原因在endPtr
- 循环测试中,while
和range
包含的文本长度差为0。