Mich
Mich

Reputation: 3594

How to restore Caret position or Change color of text without making a selection in RichTextBox

This has been an issue with many of my applications and I don't know why Windows doesn't have an elegant solution for this.

I am working with Winforms in .Net 4.5 in VS2013

For example, I would like to change the color of one line of text in a multiline RichTextBox.

For this I am required to set the selection using something like

rtb.Select(rtb.GetFirstCharIndexFromLine(r), str.Length);

Then, I would set the color using

rtb.SelectionColor = Color.Red;

And presumably, cancel the selection with

rtb.DeselectAll();

Now the problem is the cursor/caret has moved back to the beginning of the line,

I try to fix it by saving the previous Caret Position,

rtb.CaretPosition

However, CaretPosition is not a method of RichTextBox, and everywhere online this is the primary method everyone uses.

I tried adding PresentationFramework to my References and to my code I added

using System.Windows.Framework;

As suggested here: http://msdn.microsoft.com/en-us/library/system.windows.controls.richtextbox.caretposition(v=vs.110).aspx

but I still do not see the CaretPosition property, only the ScrollToCaret() method.

My 2 questions are:

  1. How do I get the CaretPosition property in my RichTextBox?

  2. How can I change the text color without using selections and affecting the caret position, having to write complex logic to restore it for the user.

My application checks serial numbers, one per line, and highlights them red if they do not match the format, as shown below.

private void rtb_TextChanged(object sender, EventArgs e)
    {
        string pattern = @"[A-Z]{2}[A-Z, 0-9]{2}\d{4}";
        Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);

        TextReader read = new System.IO.StringReader(rtb.Text);
        SerialNumbers.Clear();
        int selectStart = 0;

        for (int r = 0; r < rtb.Lines.Length; r++)
        {
            string str = read.ReadLine();

            if (str != null)
            {

                selectStart += str.Length;
                MatchCollection matches = rgx.Matches(str);
                if (matches.Count == 1)
                {
                    SerialNumbers.Add(str);
                }
                else
                {
                    rtb.Select(rtb.GetFirstCharIndexFromLine(r), str.Length);
                    rtb.SelectionColor = Color.Red;
                    rtb.DeselectAll();
                }

            }
        }
     }

Upvotes: 1

Views: 2448

Answers (2)

Mich
Mich

Reputation: 3594

Fixed it by saving SelectionStart position

                int selectionStart = SNbox.SelectionStart;

                SNbox.Select(SNbox.GetFirstCharIndexFromLine(r), str.Length);
                SNbox.SelectionColor = Color.Red;
                SNbox.DeselectAll();

                SNbox.SelectionStart = selectionStart;
                SNbox.SelectionLength = 0;

Upvotes: 2

Forest Kunecke
Forest Kunecke

Reputation: 2160

You should be using SelectionCaret (as @Mangist mentioned in a comment) because you're using WinForms and not WPF. The MSDN article you referenced only applies to WPF, which is very different from WinForms.

As an example, I use the following to easily log to a rich text box from anywhere in a WinForms app:

public static void Log(string text, ref RichTextBox rtbLogBox) {
    //
    if (text == null) return;

    var timestamp = DateTime.Now.ToLongTimeString();
    var logtext = string.Format("{0}    -   {1}\r\n\r\n", timestamp, text);
    if (rtbLogBox.InvokeRequired) {
        var logBox = rtbLogBox;
        logBox.Invoke(new MethodInvoker(delegate {
            logBox.AppendText(logtext);
            logBox.Update();
            logBox.SelectionStart = logBox.Text.Length;
            logBox.ScrollToCaret();
        }));
    } else {
        rtbLogBox.AppendText(logtext);
        rtbLogBox.Update();
        rtbLogBox.SelectionStart = rtbLogBox.Text.Length;
        rtbLogBox.ScrollToCaret();
    }
}

Notice how the ScrollToCaret() is called after setting SelectionStart to the length of text in the rich text box. This solves the 'issue' of AppendText not scrolling to the bottom after adding text.

In your case you will simply want to save the SelectionStart value before you format your text with the highlighting, and then restore it once you've finished.

Upvotes: 1

Related Questions