制作一个简单的搜索function,使光标跳转到(或突出显示)搜索的单词

我现在用了很长时间,试图找出问题,我认为这不会那么难。

这是交易:

我正在使用C#和WPF编写一个小应用程序。

我有一个包含FlowDocument的RichTextBox。

我在我的richtextbox下面添加了一个小文本框和一个按钮。

然后,用户键入他/她希望搜索的单词,并按下按钮。

然后,richtextbox将跳转到该单词的第一个出现位置。

它只是跳转到正确的行就足够了 – 它也可以选择,突出显示或放置光标 – 只要将richTextBox滚动到该单词,任何操作都可以。

继续按下按钮,然后跳转到该单词的下一个出现,依此类推,直到文档结束。

正如我所说 – 我认为这是一项简单的任务 – 但是我遇到了严重的问题。

这应该做的工作:

public bool DoSearch(RichTextBox richTextBox, string searchText, bool searchNext) { TextRange searchRange; // Get the range to search if(searchNext) searchRange = new TextRange( richTextBox.Selection.Start.GetPositionAtOffset(1), richTextBox.Document.ContentEnd); else searchRange = new TextRange( richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd); // Do the search TextRange foundRange = FindTextInRange(searchRange, searchText); if(foundRange==null) return false; // Select the found range richTextBox.Selection.Select(foundRange.Start, foundRange.End); return true; } public TextRange FindTextInRange(TextRange searchRange, string searchText) { // Search the text with IndexOf int offset = searchRange.Text.IndexOf(searchText); if(offset<0) return null; // Not found // Try to select the text as a contiguous range for(TextPointer start = searchRange.Start.GetPositionAtOffset(offset); start != searchRange.End; start = start.GetPositionAtOffset(1)) { TextRange result = new TextRange(start, start.GetPositionAtOffset(searchText.Length); if(result.Text == searchText) return result; } return null; } 

FindTextInRange中for()循环的原因遗憾的是,range.Text删除了非文本字符,因此在某些情况下,IndexOf计算的偏移量将略微过低。

我使用了不同的方法。 使用TextBox设置关键字; 这将搜索Button Click上的KeyWord。 找到关键字; 突出显示它并关注KeyWord。

  // Index of Current Result Found (Counts Characters not Lines or Results) private int IndexOfSearchResultFound; // Start Position Index of RichTextBox (Initiated as 0 : Beggining of Text / 1st Char) private int StartOfSelectedKeyword; private int EndOfSelectedKeyword; private void btnSearch_Click(object sender, EventArgs e) { // Reset Keyword Selection Index. (0 is the Staring Point of the Keyword Selection) IndexOfSearchResultFound = 0; // Specify the End of the Selected Keyword; using txt_Search.Text.Lenght (Char Ammount). EndOfSelectedKeyword = txt_Search.Text.Length; // If txt_Search.Text is not Empty if (txt_Search.Text.Length > 0) { // Find Keyword in RichTextBox.Text IndexOfSearchResultFound = FindKeyword(txt_Search.Text.Trim(), StartOfSelectedKeyword, rtb_Hosts.Text.Length); // If string was found in RichTextBox; Highlight it and Focus on Keyword Found Location if (IndexOfSearchResultFound >= 0) { // Focus on Currently Found Result rtb_Hosts.Focus(); // Highlight the search string rtb_Hosts.Select(IndexOfSearchResultFound, EndOfSelectedKeyword); // Sets a new Starting Position (after the Position of the Last Result Found) // To be Ready to Focus on the Next Result StartOfSelectedKeyword = IndexOfSearchResultFound + EndOfSelectedKeyword; } } } private int FindKeyword(string _SearchKeyword, int _KeywordSelectionStart, int _KeywordSelectionEnd) { // De-Select Previous Searched String (Keyword) if (_KeywordSelectionStart > 0 && _KeywordSelectionEnd > 0 && IndexOfSearchResultFound >= 0) { rtb_Hosts.Undo(); } // Set the return value to -1 by default. int retVal = -1; // A valid Starting index should be specified. // if indexOfSearchText = -1, Means that Search has reached the end of Document if (_KeywordSelectionStart >= 0 && IndexOfSearchResultFound >= 0) { // Find Keyword IndexOfSearchResultFound = rtb_Hosts.Find(_SearchKeyword, _KeywordSelectionStart, _KeywordSelectionEnd, RichTextBoxFinds.None); // Determine whether the text was found in richTextBox retVal = IndexOfSearchResultFound; } // Return the index to the specified Keyword text. return retVal; } 

我唯一无法实现的是返回第一个搜索结果

这是一种变体,可以找到最接近Caret位置的匹配。

  private TextRange FindText(string findText) { var fullText = DoGetAllText(); if (string.IsNullOrEmpty(findText) || string.IsNullOrEmpty(fullText) || findText.Length > fullText.Length) return null; var textbox = GetTextbox(); var leftPos = textbox.CaretPosition; var rightPos = textbox.CaretPosition; while (true) { var previous = leftPos.GetNextInsertionPosition(LogicalDirection.Backward); var next = rightPos.GetNextInsertionPosition(LogicalDirection.Forward); if (previous == null && next == null) return null; //can no longer move outward in either direction and text wasn't found if (previous != null) leftPos = previous; if (next != null) rightPos = next; var range = new TextRange(leftPos, rightPos); var offset = range.Text.IndexOf(findText, StringComparison.InvariantCultureIgnoreCase); if (offset < 0) continue; //text not found, continue to move outward //rtf has broken text indexes that often come up too low due to not considering hidden chars. Increment up until we find the real position var findTextLower = findText.ToLower(); var endOfDoc = textbox.Document.ContentEnd.GetNextInsertionPosition(LogicalDirection.Backward); for (var start = range.Start.GetPositionAtOffset(offset); start != endOfDoc; start = start.GetPositionAtOffset(1)) { var result = new TextRange(start, start.GetPositionAtOffset(findText.Length)); if (result.Text?.ToLower() == findTextLower) { return result; } } } } 

如果你想突出显示匹配,那么就像将此方法更改为void并在找到匹配时执行此操作一样简单:

 textbox.Selection.Select(result.Start, result.End);