Выделите текст в RichTextBox - PullRequest
13 голосов
/ 16 апреля 2011

Я пытаюсь использовать RichTextBox и мое первое чувство: «Что это сложно использовать!» ... Удивительно ...

Поэтому я пытаюсь выделить текст, содержащийся в моем RichTextBox.

В настоящее время у меня есть следующий код:

TextRange range = new TextRange(MyTextInput.Document.ContentStart, MyTextInput.Document.ContentEnd);
range.Text = @"TOP a multiline text or file END";
Regex reg = new Regex("(top|file|end)", RegexOptions.Compiled | RegexOptions.IgnoreCase);

foreach (Match match in reg.Matches(range.Text))
{
    TextPointer start = range.Start.GetPositionAtOffset(match.Index, LogicalDirection.Forward);
    TextPointer end = range.Start.GetPositionAtOffset(match.Index + match.Length, LogicalDirection.Backward);
    // text contains the exact match I want
    string text = range.Text.Substring(match.Index, match.Length);
    // here the highlighted text isn't the text I searched...
    TextRange textrange = new TextRange(start, end);
    textrange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Blue));
    textrange.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
}

TOP правильно выделен, но не file или end, но выделите меня or.

Есть предложения?

1 Ответ

18 голосов
/ 17 апреля 2011

Вы должны представить, что RichTextBox делает под капотом, чтобы понять поведение.Я не знаю точно, но я представляю следующее: Строка 1-2 устанавливается как Содержимое RichTextBox a Paragraph с Run.

Затем с первой итерацией с ApplyPropertyValue СодержимоеRichTextBox меняется!Теперь он содержит Paragraph с SpanRun внутри) и прогоном.

А затем вы должны рассмотреть расхождение между совпадением с регулярным выражением и GetPositionAtOffset.Соответствие Regex возвращает индекс для позиции символа в строке.

GetPositionAtOffset использует "Смещение в символах, для которого вычисляется и возвращается позиция" , где символ:

  • Открывающий или закрывающий тег для элемента TextElement.
  • Элемент UIElement, содержащийся в InlineUIContainer или BlockUIContainer.Обратите внимание, что такой UIElement всегда считается ровно одним символом;любое дополнительное содержимое или элементы, содержащиеся в UIElement, не считаются символами.
  • 16-битный символ Unicode внутри текстового элемента Run.

Так что вы можетехочу сделать что-то вроде этого:

TextRange range = new TextRange(MyTextInput.Document.ContentStart, MyTextInput.Document.ContentEnd);
range.Text = @"TOP a multiline text or file END";
Regex reg = new Regex("(top|file|end)", RegexOptions.Compiled | RegexOptions.IgnoreCase);

var start = MyTextInput.Document.ContentStart;
while (start != null && start.CompareTo(MyTextInput.Document.ContentEnd) < 0)
{
    if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
    {
        var match=reg.Match(start.GetTextInRun(LogicalDirection.Forward));

        var textrange = new TextRange(start.GetPositionAtOffset(match.Index, LogicalDirection.Forward), start.GetPositionAtOffset(match.Index + match.Length, LogicalDirection.Backward));
        textrange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Blue));
        textrange.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
        start= textrange.End; // I'm not sure if this is correct or skips ahead too far, try it out!!!
    }
    start = start.GetNextContextPosition(LogicalDirection.Forward);
}

* Отказ от ответственности: я не пробовал это, так как сейчас я не близко к среде разработки.Я даже не знаю, компилируется ли это, но я надеюсь на это.

...