WPF FlowDocument-абсолютная позиция символа
У меня есть WPF RichTextBox, в который я набираю текст, а затем разбираю весь текст для обработки. Во время этого разбора у меня есть абсолютные позиции символов начала и конца каждого слова.
Я хотел бы использовать эти позиции символов для применения форматирования к определенным словам. Однако я обнаружил, что FlowDocument использует экземпляры TextPointer для пометки позиций в документе.
Я обнаружил, что могу создать TextRange с помощью построение его с помощью указателей начала и конца. Как только у меня есть TextRange, я могу легко применить форматирование к тексту внутри него. Я использую GetPositionAtOffset для получения TextPointer для смещения моего символа, но подозреваю, что его смещение отличается от моего, потому что выбранный текст находится в несколько ином положении, чем я ожидаю.
мой вопрос в том, как я могу точно преобразовать абсолютную позицию символа в TextPointer?
3 ответов
Я не нашел надежного способа преобразования абсолютных позиций символов в экземпляры 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);
}
У меня также была эта проблема и закончилась следующим методом расширения 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;
}
У меня была точно такая же проблема, я узнал, что в RichTextBox есть ошибка, потому что она не учитывает "новые символы строки - \r\n", так как ваши номера строк увеличиваются, вы обнаружите, что ваше смещение расположено неправильно по количеству номеров строк, и я решил свои проблемы путем смещения номера строки из смещения.