0

I am trying to implement programmatically selected (using regex) text formatting in a WPF RichTextBox. The use case is simply a WPF RichTextBox in which the user types text. However, to improve or accelerate readability i want to incorporate some automatic formatting as the text is typed.

The following code from How to select text from the RichTextBox and then color it? is exactly what i am trying to do. However, as far as i can tell this code is for a WinForms RichTextBox:

public void ColourRrbText(RichTextBox rtb)
{
    Regex regExp = new Regex(@"\b(For|Next|If|Then)\b");

    foreach (Match match in regExp.Matches(rtb.Text))
    {
        rtb.Select(match.Index, match.Length);
        rtb.SelectionColor = Color.Blue;
    }
}

I have tried to convert it as follows:

public static void ColorSpecificText(RichTextBox rtb)
{
    TextRange textRange = new TextRange(rtb.Document.ContentEnd, rtb.Document.ContentEnd);

    Regex regex = new Regex(@"\b(For|Next|If|Then)\b");

    foreach (Match match in regex.Matches(textRange.Text))
    { 
        textRange.Select(match.Index, match.Length); // <--- DOESN'T WORK
        textRange.SelectionColor = Color.Blue; // <--- DOESN'T WORK
    }
}

However, i am stuck on how to convert the "match.Index, match.Length" and the "SelectionColor" syntax to something that the WPF RichTextBox knows how to handle. I have searched other posts, but most also seem to be for WinForms RichTextBox, not WPF. Any guidance would be greatly appreciated.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • To use a word boundary, use verbartim string literal, or double the backslash, `@"\b(For|Next|If|Then)\b"` – Wiktor Stribiżew Apr 16 '20 at 13:19
  • Thanks @Wiktor. You are right the @ is needed. But that does not solve the issue with match.index, match length which yields error code "cannot convert from int to 'System.Windows.Documents.TextPointer'". – scorpiotomse Apr 16 '20 at 13:24
  • Thaty is already not a regex issue. Please modify the question. What type of value does `textRange.Select` expect? The `SelectionColor` seems to expect `System.Drawing.Color`. But that migth affect the whole component text, not just a part of it. – Wiktor Stribiżew Apr 16 '20 at 13:30
  • i agree - this is not a regex issue. textRange.Select take two TextPointers. My question is what is the syntax to specify the match.index and the match.length using TextPointers. – scorpiotomse Apr 16 '20 at 13:35
  • @scorpiotomse if an answer solves your question, please click on the tick mark to let other people know this problem is solved. – Bizhan Apr 16 '20 at 15:54

1 Answers1

1

This is the syntax:

TextRange textRange = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd);
textRange.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Black);
Regex regex = new Regex(@"\b(For|Next|If|Then)\b");

int i = 0;
foreach (Match match in regex.Matches(textRange.Text))
{
    var wordStartOffset = textRange.Start.GetPositionAtOffset(i + match.Index);
    var wordEndOffset = textRange.Start.GetPositionAtOffset(i + match.Index + match.Length);
    var wordRange = new TextRange(wordStartOffset, wordEndOffset);
    wordRange.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.LightBlue);
    i += 4; // could be something else
}

Although it may not highlight correctly because of your strategy. I'm afraid string index is not enough to create the proper TextPointer. +4 is used to skip formatting overheads, that's why it may not work if other formattings are present.

Bizhan
  • 16,157
  • 9
  • 63
  • 101
  • Hi @Bizhan: super helpful. It works. Really appreciate it. Will dive into your code to better understand. What do you mean by "is not enough to create the proper TextPointer?" What would be the proper syntax? – scorpiotomse Apr 16 '20 at 16:12
  • @scorpiotomse, you're welcome. the proper way to do it mainly depends on your design. AFAIK, RTB uses a FlowDocument as its contents and all kinds of crazy things can go inside it, so it's hard to tell how much offset you need in different scenarios. I don't have much knowledge about RTB but to me the simplest way to handle it, is to find and apply each word consecutively, in contrast to find all and then apply all. – Bizhan Apr 16 '20 at 16:28
  • @scorpiotomse to clarify, if you remove this line :`ApplyPropertyValue(...black)` then there's no telling how it works. e.g. if you already have some colors or other formatting you need to remember those offsets somewhere and take them into consideration. But otherwise the code above works as it is. you can debug it and see how elements are created so that the offset moves by 4 everytime a formatting is applied – Bizhan Apr 16 '20 at 16:36
  • ok - great - thanks again. In fact i do agree to initialize the formatting each time - so the ApplyPropertyValue (... black) is completely ok. – scorpiotomse Apr 16 '20 at 17:48