2009-11-18 4 views
5

J'ai maintenant utilisé beaucoup trop de temps, en essayant de comprendre un problème, que je ne pensais pas que ce serait difficile .faire une simple fonction de recherche, en faisant passer le curseur (ou mettre en surbrillance) le mot recherché

Voici l'affaire:

Je vous écris une petite application en C# et WPF.

J'ai un RichTextBox contenant un FlowDocument.

J'ai ajouté une petite zone de texte et un bouton sous ma riche zone de texte.

L'utilisateur tape ensuite le mot qu'il souhaite rechercher et appuie sur le bouton.

La zone richtext passera alors à la première occurrence de ce mot.

il suffit de passer à la ligne correcte - il peut également sélectionner, mettre en surbrillance ou placer le curseur par le mot - tout ce qui peut être fait, tant que le richTextBox fait défiler le mot. Si vous continuez à appuyer sur le bouton, vous passerez à l'occurrence suivante du mot, et ainsi de suite, jusqu'à la fin du document. Comme je l'ai dit - je pensais que c'était une tâche simple - mais j'ai de sérieux problèmes à comprendre.

Répondre

13

Cela devrait faire le travail:

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

La raison de la for() boucle en FindTextInRangeUnfortunately les bandes Range.Text les caractères non-texte, de sorte que dans certains cas, le décalage calculé par IndexOf sera légèrement trop bas.

+0

Il a travaillé comme un charme. Merci mille fois pour votre réponse, mon pote. Tu n'as aucune idée de combien tu m'as aidé. Passez une bonne journée! – Sagi1981

+0

Le premier retour dans FindTextInRange devrait cependant il a changé à une null, au lieu d'un faux :) – Sagi1981

+2

Merci. C'est ce qui arrive quand vous tapez une idée et ne vous embêtez pas à l'essayer. J'ai édité faux -> null il dans ma réponse. –

1

J'ai utilisé une approche différente. Utilisation d'un contrôle TextBox pour définir le mot-clé; Cette recherche le KeyWord on Button Click. Recherche le mot-clé; Highlighs et se concentre sur ce 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; 
    } 

La seule chose que je ne pouvais pas atteindre encore est de revenir à la 1ère Résultat de la recherche

0

Ceci est une variante qui va trouver le match le plus proche de la position 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; 
      } 
     } 
     } 
    } 

Si vous voulez mettre en évidence le match alors ce serait aussi simple que de changer cette méthode pour annuler et de le faire lorsque vous avez trouvé le match:

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