WPF FlowDocument - 绝对字符位置

9

我有一个WPF RichTextBox,我在其中输入一些文本,然后解析整个文本以进行处理。在此解析期间,我拥有每个单词的开始和结束的绝对字符位置。

我想使用这些字符位置来应用某些单词的格式。但是,我发现FlowDocument使用TextPointer实例标记文档中的位置。

我发现可以通过使用起始和结束指针构造TextRange来创建TextRange。一旦我有了TextRange,我就可以轻松地对其中的文本应用格式。我一直在使用GetPositionAtOffset来获取我的字符偏移量的TextPointer,但怀疑它的偏移量与我的不同,因为所选文本的位置与我预期的略有不同。

我的问题是,如何准确地将绝对字符位置转换为TextPointer?


1
+1,我也遇到了完全相同的问题——正在进行自定义解析,但是高亮显示的偏移错误。 - Cameron
3个回答

10

我也曾遇到过这个问题,并最终使用以下 RichTextBox 扩展方法解决了它。在我的情况下,它运行得非常顺畅!

/// <summary>
/// Gets the text pointer at the given character offset.
/// Each line break will count as 2 chars.
/// </summary>
/// <param name="richTextBox">The rich text box.</param>
/// <param name="offset">The offset.</param>
/// <returns>The TextPointer at the given character offset</returns>
public static TextPointer GetTextPointerAtOffset(this RichTextBox richTextBox, int offset)
{
    var navigator = richTextBox.Document.ContentStart;
    int cnt = 0;

    while (navigator.CompareTo(richTextBox.Document.ContentEnd) < 0)
    {
        switch (navigator.GetPointerContext(LogicalDirection.Forward))
        {
            case TextPointerContext.ElementStart:
                break;
            case TextPointerContext.ElementEnd:
                if (navigator.GetAdjacentElement(LogicalDirection.Forward) is Paragraph)
                    cnt += 2;
                break;
            case TextPointerContext.EmbeddedElement:
                // TODO: Find out what to do here?
                cnt++;
                break;
            case TextPointerContext.Text:
                int runLength = navigator.GetTextRunLength(LogicalDirection.Forward);

                if (runLength > 0 && runLength + cnt < offset)
                {
                    cnt += runLength;
                    navigator = navigator.GetPositionAtOffset(runLength);
                    if (cnt > offset)
                        break;
                    continue;
                }
                cnt++;
                break;
        }

        if (cnt > offset)
            break;

        navigator = navigator.GetPositionAtOffset(1, LogicalDirection.Forward);

    } // End while.

    return navigator;
}

6
我没有找到一种可靠的方法将绝对字符位置转换为TextPosition实例。 我的替代解决方案是修改原始解析,使其适用于单个运行而不是捕获RichTextBox的整个文本。使用相对于特定Run实例的字符位置已经被证明非常可靠。我认为更多地将我的思维方式转向WPF的思考方式有所帮助。
我采用以下方法在FlowDocument中导航运行(受到http://blogs.msdn.com/prajakta/archive/2006/10/12/customize-richtextbox-to-allow-only-plain-text-input.aspx的启示):
// Get starting pointer
TextPointer navigator = flowDocument.ContentStart;

// While we are not at end of document
while (navigator.CompareTo(flowDocument.ContentEnd) < 0)
{
    // Get text pointer context
    TextPointerContext context = navigator.GetPointerContext(LogicalDirection.Backward);

    // Get parent as run
    Run run = navigator.Parent as Run;

    // If start of text element within run
    if (context == TextPointerContext.ElementStart && run != null)
    {
        // Get text of run
        string runText = run.Text;

        // ToDo: Parse run text
    }

    // Get next text pointer
    navigator = navigator.GetNextContextPosition(LogicalDirection.Forward);
}

1

我曾经遇到过完全相同的问题,后来发现 RichTextBox 存在一个 bug,它不会计算“换行符 - \r\n”,因此随着行号的增加,你会发现你的偏移量位置错误地受到行数计数的影响。我通过从偏移量中抵消行号来解决了我的问题。


嗨,Akash,感谢您的回复。我的经验是它确实计算了我的换行符,但我注意到完全空白的行“<Paragraph><Run xml:lang="en-gb" xml:space="preserve" /></Paragraph>”会导致FlowDocument在我的偏移量之前2个字符(在每个换行符后累积)。 - Alan Spark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接