制作一个简单的搜索功能,使光标跳转到(或突出显示)要搜索的单词
Posted
技术标签:
【中文标题】制作一个简单的搜索功能,使光标跳转到(或突出显示)要搜索的单词【英文标题】:making a simple search function, making the cursor jump to (or highlight) the word that is searched for 【发布时间】:2010-12-17 22:18:32 【问题描述】:我现在用了太长时间,试图找出一个问题,我认为这不会那么难。
这是交易:
我正在使用 C# 和 WPF 编写一个小型应用程序。
我有一个包含 FlowDocument 的 RichTextBox。
我在我的richtextbox 下方添加了一个小文本框和一个按钮。
然后用户输入他/她想要搜索的词,然后按下按钮。
richtextbox 将跳转到该单词的第一次出现。
只要跳转到正确的行就足够了——它还可以通过单词选择、突出显示或放置光标——只要richTextBox滚动到单词,任何事情都可以。
继续按下按钮,将跳转到下一个出现的单词,依此类推,直到文档结束。
正如我所说的 - 我认为这是一项简单的任务 - 但是我在解决这个问题时遇到了严重的问题。
【问题讨论】:
【参考方案1】:这应该可以完成工作:
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 计算的偏移量会略低。
【讨论】:
它就像一个魅力。谢谢你的回答一百万,伙计。你不知道你帮了我多少。祝你有美好的一天! FindTextInRange 中的第一个返回值应该改为 null,而不是 false :) 谢谢。当您输入一个想法并且不费心尝试它时,就会发生这种情况。我在我的答案中编辑了 false -> null 它。 多年后它仍然有用!谢谢 Ray,你的 FindTextInRange 方法救了我,你的 for 循环解释特别有帮助。 您好;对不起,我是个菜鸟,但是;这对我不起作用(还)。我无法获得 TextRange 的参考。我仍然假设我可以使用: rtb_Document.Lenght as Range;但似乎并非如此。至于 TextPointer 我完全一无所知。在下面的“我的”答案(现已更新)中,我实际上可以执行搜索并突出显示,但我无法:返回找到的第一个值;也不检索当前结果索引(因为结果位置是文本中的字符值)。请给我指路好吗?【参考方案2】:我使用了不同的方法。 使用文本框设置关键字;这在按钮单击时搜索关键字。 找到关键字;突出显示并专注于该关键字。
// 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;
我唯一做不到的就是返回第一个搜索结果
【讨论】:
【参考方案3】:这是一个变体,可以找到最接近插入符号位置的匹配项。
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);
【讨论】:
以上是关于制作一个简单的搜索功能,使光标跳转到(或突出显示)要搜索的单词的主要内容,如果未能解决你的问题,请参考以下文章