WPF FlowDocument - Абсолютная позиция символа - PullRequest
9 голосов
/ 02 апреля 2010

У меня есть WPF RichTextBox, в который я набираю некоторый текст, а затем анализирую весь текст для дальнейшей обработки. Во время этого анализа у меня есть абсолютные позиции символов начала и конца каждого слова.

Я хотел бы использовать эти позиции символов для применения форматирования к определенным словам. Однако я обнаружил, что FlowDocument использует экземпляры TextPointer для маркировки позиций в документе.

Я обнаружил, что могу создать TextRange, создав его с помощью указателей начала и конца. Когда у меня есть TextRange, я могу легко применить форматирование к тексту внутри него. Я использовал GetPositionAtOffset, чтобы получить TextPointer для моего смещения символа, но подозреваю, что его смещение отличается от моего, потому что выделенный текст находится немного в другом положении, чем я ожидаю.

Мой вопрос: как я могу точно преобразовать абсолютную позицию символа в TextPointer?

Ответы [ 3 ]

6 голосов
/ 05 апреля 2010

Я не нашел надежного способа преобразования абсолютных позиций символов в экземпляры 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);
}
6 голосов
/ 11 октября 2014

У меня также была эта проблема, и в результате я использовал следующий метод расширения 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;
}
1 голос
/ 02 апреля 2010

У меня была точно такая же проблема, я обнаружил, что есть ошибка в RichTextBox, потому что он не учитывает "символы новой строки - \ r \ n", так что при увеличении номеров строк вы обнаружите, что ваше смещение позиционировано неверно по количеству строк, и я решил свои проблемы, сместив номер строки из смещения.

...