WPF FlowDocument - 绝对字符位置

发布于 2024-08-27 15:41:06 字数 366 浏览 9 评论 0原文

我有一个 WPF RichTextBox,我正在其中输入一些文本,然后解析整个文本以进行处理。在此解析过程中,我获得了每个单词的开头和结尾的绝对字符位置。

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

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

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

I have a WPF RichTextBox that I am typing some text into and then parsing the whole of the text to do processing on. During this parse, I have the absolute character positions of the start and end of each word.

I would like to use these character positions to apply formatting to certain words. However, I have discovered that the FlowDocument uses TextPointer instances to mark positions in the document.

I have found that I can create a TextRange by constructing it with start and end pointers. Once I have the TextRange I can easily apply formatting to the text within it. I have been using GetPositionAtOffset to get a TextPointer for my character offset but suspect that its offset is different from mine because the selected text is in a slightly different position from what I expect.

My question is, how can I accurately convert an absolute character position to a TextPointer?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

三生池水覆流年 2024-09-03 15:41:06

我也遇到过这个问题,最终得到了以下 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;
}

I have also had this problem and has ended up with the following RichTextBox extension method. In my context it work flawlessly!

/// <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;
}
怪我闹别瞎闹 2024-09-03 15:41:06

我没有找到将绝对字符位置转换为 TextPosition 实例的可靠方法。

我的替代解决方案是修改原始解析以在单独的运行中工作,而不是捕获 RichTextBox 的整个文本。事实证明,使用与特定运行实例相关的角色位置对我来说是可靠的。我认为将我的思维方式更多地转向 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);
}

I didn't find a reliable way of converting absolute character positions into TextPosition instances.

My alternative solution was to modify the original parse to work on individual runs rather than capturing the whole text of the RichTextBox. Working with character positions that are relative to a specific Run instance has proved reliable for me. I think that moving my mindset more towards the WPF way of thinking has helped.

I took the following approach for navigating runs in the FlowDocument (inspired by 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);
}
心如狂蝶 2024-09-03 15:41:06

我有完全相同的问题,我发现RichTextBox中有一个错误,因为它不计算“换行符 - \r\n”,所以随着行号的增加,你会发现你的偏移量按行定位错误数量计数,我通过从偏移量中偏移行号解决了我的问题。

I had exact similar problem, I found out that there is a bug in RichTextBox because it does not count "new line characters - \r\n", so as your line numbers increase, you will find that your offset is positioned wrong by line number count, and I had solved my problems by offsetting line number from offset.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文