2009-11-18 3 views
5

Użyłem teraz zbyt długo, próbując wykombinować problem, który nie wydawał mi się tak trudny .tworząc prostą funkcję wyszukiwania, dzięki czemu kursor przeskoczy do (lub podświetli) szukane słowo

Oto sprawa:

Piszę małych aplikacji przy użyciu C# i WPF.

Mam RichTextBox zawierający FlowDocument.

Dodałem mały pole tekstowe i przycisk poniżej mojego richtextbox.

Użytkownik wpisuje słowo, które chce wyszukać, i naciska przycisk.

Richtextbox przeskoczy do pierwszego wystąpienia tego słowa.

wystarczy, że po prostu przeskoczy do właściwej linii - może również wybrać, zaznaczyć lub umieścić kursor za pomocą słowa - wszystko będzie działać, dopóki tekst richTextBox zostanie przewinięty do słowa.

Naciśnięcie przycisku spowoduje przejście do następnego wystąpienia słowa i tak dalej, aż do końca dokumentu.

Jak już powiedziałem - myślałem, że to proste zadanie - jednak mam poważne problemy z ustaleniem tego.

Odpowiedz

13

To powinno załatwić sprawę:

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; 
} 

Powodem dla() pętli w FindTextInRangeUnfortunately range.Text pozbawia się znaki inne niż tekstowe, więc w niektórych przypadkach przesunięcie obliczane przez IndexOf będzie nieco za nisko.

+0

to działało jak czar. Dzięki za odpowiedź na milion, kolego. Nie masz pojęcia, jak bardzo mi pomogłeś. Miłego dnia! – Sagi1981

+0

Pierwszy zwrot w FindTextInRange powinien jednak zostać zmieniony na wartość zerową, zamiast fałszywego :) – Sagi1981

+2

Dzięki. Tak dzieje się, gdy wpiszesz pomysł i nie próbujesz go wypróbować. Edytowałem false -> null it w mojej odpowiedzi. –

1

Użyłem innego podejścia. Korzystanie z pola tekstowego do ustawienia słowa kluczowego; to wyszukuje KeyWord po kliknięciu przycisku. Znajduje słowo kluczowe; Highlighs it i koncentruje się na tym 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; 
    } 

Jedyną rzeczą, nie mogę jeszcze osiągnąć to, aby powrócić do 1 wynik wyszukiwania

0

Jest to wariant, który znajdzie meczu najbliżej pozycji użyciu kursora.

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; 
      } 
     } 
     } 
    } 

Jeśli chcesz wyróżnić mecz to byłoby tak proste, jak zmiana tej metody do unieważnienia i robi to, gdy okazało się, że mecz:

textbox.Selection.Select(result.Start, result.End); 
Powiązane problemy