Using WinForms, I have a RichTextBox which will hold the contents of a text file whose length will be limited only by what a RichTextBox can manage.
A section within it will be marked using a certain background color. I need to quickly identify where the section begins and ends. I don't trust that the section will be completely unbroken, and the marked area might cover the entire text--so I need to examine the background color of every character.
The obvious way to do this is to select each character in turn and get its SelectionBackColor:
private TextRange? CalcMarkedTextRange() {
var rtb = RichTextBox;
var textLength = rtb.TextLength;
// Store the range of whatever the user currently has selected
var currentSelectionRange = new TextRange( rtb );
rtb.Visible = false; // <--- To prevent slow screen updates
// Find where the first and last color-marked characters are
var markBegins = -1;
var markEnds = -1;
for ( int ix = 0; ix < textLength; ++ix ) {
rtb.Select( ix, 1 );
if ( rtb.SelectionBackColor == SelectedTextBackColor ) {
if ( markBegins == -1 ) {
markBegins = ix;
}
markEnds = ix;
}
}
// Put back user's selection
rtb.Select( currentSelectionRange );
rtb.Visible = true;
// See what we found
if ( markBegins > -1 ) {
// Return a single range encompassing all marked characters
return new TextRange( markBegins, markEnds - markBegins + 1 );
}
return null;
}
In the code above, TextRange
is a structure that stores the start and length of a selection, just as you might expect.
If I don't hide the control by messing with its Visible
property before scanning the colors, this code is unbelievably slow. You can see it scanning through, even with a relatively small amount of text. My test using about 4000 characters exhibited unacceptably poor performance.
I do hide it, it operates much more quickly, but there is still an ugly flash as the control disappears for a few seconds then comes back with its scroll position slightly off.
There must be a way to know the background color of an individual character without having to select it, though I imagine one would have to call a native Win32 method. But I have had no luck finding one.