How to select RichTextBox text given an index and length

l46kok picture l46kok · Aug 22, 2012 · Viewed 7.3k times · Source

If you are only given an index and length (or EndIndex) of a certain text to select, how do you perform this in WPF version of RichTextBox?

This is very doable in Textbox as you can call Textbox.Select(startIndex,Length) but I don't see anything equivalent in RTB.

Edit: I have found the answer to making a selection

internal string Select(RichTextBox rtb, int index, int length)
        {
            TextRange textRange = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd);

            if (textRange.Text.Length >= (index + length))
            {
                TextPointer start = textRange.Start.GetPositionAtOffset(index, LogicalDirection.Forward);
                TextPointer end = textRange.Start.GetPositionAtOffset(index + length, LogicalDirection.Backward);
                rtb.Selection.Select(start, end);
            }
            return rtb.Selection.Text;
        } 

However, when I try to highlight the line after the selection has been made:

rtb.Selection.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.LightBlue));

The highlighting feature works only on the first try and breaks after second try. Anyone know the reason for this?

Answer

CSharpie picture CSharpie · Jul 31, 2014

Ok this question is old but i finally found the Answer so i put this here.

I was having similiar issues when i tried to make some Syntaxhighlighter using the RichTextBox. What I found out is, that when you play arround with ApplyPropertyValue you cannot simply use GetPositionAtOffset anymore. I believe that applying propertyvalues seems to change the "internal positions" of TextTokens inside the Document, hence 'braking' this functionality.

The Workaround:

Everytime you need to work with GetPositionAtOffset first call ClearAllProperties on the complete TextRange of the Document, then reapply all your properties using ApplyPropertyValue but thistime from right to left. (right means highest offset)

I dont know if you had applied any PropertyValues expect the Selection highlighting, so you might need to put more thinking inthere.

This is how my code looked when it caused the Problem:

    private void _highlightTokens(FlowDocument document)
    {
        TextRange fullRange = new TextRange(document.ContentStart, document.ContentEnd);
        foreach (Token token in _tokenizer.GetTokens(fullRange.Text))
        {
            TextPointer start = fullRange.Start.GetPositionAtOffset(token.Position);
            TextPointer end = start.GetPositionAtOffset(token.Length);

            TextRange range = new TextRange(start, end);
            range.ApplyPropertyValue(TextElement.ForegroundProperty, _getTokenColor(token));
        }
    }

And i fixed it like this:

    private void _highlightTokens(FlowDocument document)
    {
        TextRange fullRange = new TextRange(document.ContentStart, document.ContentEnd);
        fullRange.ClearAllProperties(); // NOTICE: first remove allProperties.
        foreach (Token token in _tokenizer.GetTokens(fullRange.Text).Reverse()) // NOTICE: Reverse() to make the "right to left" work
        {
            TextPointer start = fullRange.Start.GetPositionAtOffset(token.Position);
            TextPointer end = start.GetPositionAtOffset(token.Length);

            TextRange range = new TextRange(start, end);
            range.ApplyPropertyValue(TextElement.ForegroundProperty, _getTokenColor(token));
        }
    }