간단한 검색 함수 만들기, 커서가 검색 된 단어로 점프 (또는 강조)
-
20-09-2019 - |
문제
나는 지금 너무 오랫동안 사용하여 문제를 알아 내려고 노력했습니다.
거래는 다음과 같습니다.
C# 및 WPF를 사용하여 작은 응용 프로그램을 작성하고 있습니다.
FlowDocument가 포함 된 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 () 루프의 이유 불행히도 범위는 텍스트가 아닌 문자를 제거하므로 경우에 따라 indexof에 의해 계산 된 오프셋이 약간 낮습니다.
다른 팁
나는 다른 접근법을 사용했습니다. 텍스트 상자를 사용하여 키워드를 설정합니다. 버튼 클릭의 키워드를 검색합니다. 키워드를 찾습니다. Highlighs를하고 그 키워드에 중점을 둡니다.
// 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;
}
아직 달성 할 수 없었던 유일한 것은 첫 번째 검색 결과로 돌아가는 것입니다.
이것은 일치를 찾을 수있는 변형입니다 캐럿 위치에 가장 가깝습니다.
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;
}
}
}
}
경기를 강조하려면 경기를 찾을 때이 방법을 무효화하고이 작업을 수행하는 것만 큼 간단합니다.
textbox.Selection.Select(result.Start, result.End);