4

I have a RichTextBox, and there are about more than 1000 occurrences of a specified search string.

I use the following function to color all the occurrences:

public void ColorAll(string s)
{
    rtbxContent.BeginUpdate();

    int start = 0, current = 0;
    RichTextBoxFinds options = RichTextBoxFinds.MatchCase;
    start = rtbxContent.Find(s, start, options);
    while (start >= 0)
    {
        rtbxContent.SelectionStart  = start;
        rtbxContent.SelectionLength = s.Length;
        rtbxContent.SelectionColor     = Color.Red;
        rtbxContent.SelectionBackColor = Color.Yellow;

        current = start + s.Length;
        if (current < rtbxContent.TextLength)
            start = rtbxContent.Find(s, current, options);
        else
            break;
    }

    rtbxContent.EndUpdate();
}

But I found it's very slow.

However, if I color all the occurrences of another word, which has less number of occurrences in the same text, I found it's very fast.

So I guess the slowness is from (these two line might get UI refresh involved):

    rtbxContent.SelectionColor     = Color.Red;
    rtbxContent.SelectionBackColor = Color.Yellow;

Is there a faster way of doing the same job, such as, I do the coloring in the memory, and then I display the result at one-go?

Do I make myself clear?

Thanks.

Peter Lee
  • 12,931
  • 11
  • 73
  • 100

4 Answers4

2

There is a faster way.

Use regex to find the matches then highlight in the richtextbox

    if (this.tBoxFind.Text.Length > 0)
    {
        try
        {
               this.richTBox.SuspendLayout();
               this.Cursor = Cursors.WaitCursor;

           string s = this.richTBox.Text;
           System.Text.RegularExpressions.MatchCollection mColl = System.Text.RegularExpressions.Regex.Matches(s, this.tBoxFind.Text);

           foreach (System.Text.RegularExpressions.Match g in mColl)
           {
                  this.richTBox.SelectionColor = Color.White;
                  this.richTBox.SelectionBackColor = Color.Blue;

                  this.richTBox.Select(g.Index, g.Length);
           }
   }
   finally
   {
         this.richTBox.ResumeLayout();
         this.Cursor = Cursors.Default;
   }
}
Ian---
  • 63
  • 5
1

The amount of time it takes is directly proportional to the number of occurances.

It is probably the Find that is using the most time. You could replace this line:

    start = rtbxContent.Find(s, start + s.Length, options); 

with this:

    start = rtbxContent.Find(s, current, options);

Since you have computed current to equal start + s.Length

You could also store s.Length is a variable so you do not need to count all the characters in a string each time. The same goes for rtbxContent.TextLength.

Shiraz Bhaiji
  • 64,065
  • 34
  • 143
  • 252
0

You're on the right track that Winforms' slow RichTextBox implementation is to blame. You also did well to use the BeginUpdate and EndUpdate methods (I'm guessing you took those from here?). But alas, that isn't enough.

A couple of solutions:

1: Try writing the RTF directly to the textbox. This is a fairly messy, complicated format, but luckily, I have created an answer here which will do the trick.

2: This highly rated external project also looks well worth a look: http://www.codeproject.com/Articles/161871/Fast-Colored-TextBox-for-syntax-highlighting

Community
  • 1
  • 1
Dan W
  • 3,520
  • 7
  • 42
  • 69
0

The string search is linear. If you find Find method to be slow, maybe you can use third party tool to do the searching for you. All you need is index of the pattern in a string.

Maybe this will help you. You should time the difference and use the faster one.

Nayan
  • 3,092
  • 25
  • 34
  • Thanks for your reply. I'm not sure whether my guess is right or not. I don't think the "Find" method is the main reason causing it so slow. I think it might be the UI update/refresh make it slow. – Peter Lee Oct 03 '10 at 22:33
  • Then why don't you time the individual code pieces? You'll know where the problem might be. – Nayan Oct 04 '10 at 05:43