Reputation: 71
I found the following code http://www.dotnetcurry.com/showarticle.aspx?ID=146 and implemented it into my app, however it only finds the string once and to continue looking for other instances of the string you have to keep pressing the search button (bit tedious with 100's of matches).
I'd like to find all instances of the search string and if possible highlight each line, failing that highlight the string item like this code already does but all instances not just one.
On the link above there is possibly a solution down further on the page but it's in VB which I don't know how to convert to C#.
private void btnListSearch_Click(object sender, EventArgs e)
{
int startindex = 0;
if (txtSearch.Text.Length > 0)
startindex = FindMyText(txtSearch.Text.Trim(), start, rtb.Text.Length);
// If string was found in the RichTextBox, highlight it
if (startindex >= 0)
{
// Set the highlight color as red
rtb.SelectionColor = Color.Red;
// Find the end index. End Index = number of characters in textbox
int endindex = txtSearch.Text.Length;
// Highlight the search string
rtb.Focus();
rtb.Select(startindex, endindex);
// mark the start position after the position of
// last search string
start = startindex + endindex;
}
}
public int FindMyText(string txtToSearch, int searchStart, int searchEnd)
{
// Unselect the previously searched string
if (searchStart > 0 && searchEnd > 0 && indexOfSearchText >= 0)
{
rtb.Undo();
}
// Set the return value to -1 by default.
int retVal = -1;
// A valid starting index should be specified.
// if indexOfSearchText = -1, the end of search
if (searchStart >= 0 && indexOfSearchText >=0)
{
// A valid ending index
if (searchEnd > searchStart || searchEnd == -1)
{
// Find the position of search string in RichTextBox
indexOfSearchText = rtb.Find(txtToSearch, searchStart, searchEnd, RichTextBoxFinds.None);
// Determine whether the text was found in richTextBox1.
if (indexOfSearchText != -1)
{
// Return the index to the specified search text.
retVal = indexOfSearchText;
}
}
}
return retVal;
}
private void txtSearch_TextChanged(object sender, EventArgs e)
{
// Reset the richtextbox when user changes the search string
start = 0;
indexOfSearchText = 0;
}
I also tried to search a listbox but it would only find strings at the start of a line not along the line.
string searchString = textBox2.Text;
listBoxResults.SelectionMode = SelectionMode.MultiExtended;
// Set our intial index variable to -1.
int x = -1;
// If the search string is empty exit.
if (searchString.Length != 0)
{
// Loop through and find each item that matches the search string.
do
{
// Retrieve the item based on the previous index found. Starts with -1 which searches start.
x = listBoxResults.FindString(searchString, x);
// If no item is found that matches exit.
if (x != -1)
{
// Since the FindString loops infinitely, determine if we found first item again and exit.
if (listBoxResults.SelectedIndices.Count > 0)
{
if (x == listBoxResults.SelectedIndices[0])
return;
}
// Select the item in the ListBox once it is found.
listBoxResults.SetSelected(x, true);
}
} while (x != -1);
}
Upvotes: 1
Views: 4625
Reputation: 54453
Your code has a few problems.
You call the search and selection routines only once per button click, so only one occurrence can be found each time. If you want to highlight all occurrences you need to create a loop
You undo each change in the FindMyText
method. That makes no sense. You may want to clear all selections before you search something new, but not while searching
You set the selection color before setting the selection. This will do nothing, at best..
Here is a version which stores all positions in a list and supports two buttons to go forward and backward through the list..:
List<int> found = null;
private void cb_findAll_Click(object sender, EventArgs e)
{
int cursorPos = rtb.SelectionStart;
clearHighlights(rtb);
found = FindAll(rtb, txtSearch.Text, 0);
HighlightAll(rtb, Color.Red, found, txtSearch.Text.Length);
rtb.Select(cursorPos, 0);
}
private void cb_findNext_Click(object sender, EventArgs e)
{
int pos = -1;
for (int f = 0; f < found.Count; f++)
if (found[f] > rtb.SelectionStart) { pos = found[f]; break; }
if (pos >= 0) rtb.Select(pos, txtSearch.Text.Length);
rtb.ScrollToCaret();
}
private void cb_findPrev_Click(object sender, EventArgs e)
{
int pos = -1;
for (int f = 0; f < found.Count; f++)
if (found[f] >= rtb.SelectionStart) { if (f >= 1) pos = found[f - 1]; break; }
if (pos >= 0) rtb.Select(pos, txtSearch.Text.Length);
rtb.ScrollToCaret();
}
public List<int> FindAll(RichTextBox rtb, string txtToSearch, int searchStart)
{
List<int> found = new List<int>();
if (txtToSearch.Length <= 0) return found;
int pos= rtb.Find( txtToSearch, searchStart, RichTextBoxFinds.None);
while (pos >= 0)
{
found.Add(pos);
pos = rtb.Find(txtToSearch, pos + txtToSearch.Length, RichTextBoxFinds.None);
}
return found;
}
public void HighlightAll(RichTextBox rtb, Color color, List<int> found, int length)
{
foreach (int p in found)
{
rtb.Select(p, length);
rtb.SelectionColor = color;
}
}
void clearHighlights(RichTextBox rtb)
{
int cursorPos = rtb.SelectionStart; // store cursor
rtb.Select(0, rtb.TextLength); // select all
rtb.SelectionColor = rtb.ForeColor; // default text color
rtb.Select(cursorPos, 0); // reset cursor
}
private void txtSearch_TextChanged(object sender, EventArgs e)
{
found = new List<int>(); // clear list
clearHighlights(rtb); // clear highlights
}
private void rtb_TextChanged(object sender, EventArgs e)
{
found = new List<int>();
clearHighlights(rtb);
}
Note how small each piece of code is!
Upvotes: 2