2013-07-31 14 views
5

Salve a tutti quelli che ho lavorato su un'applicazione WPF con un editor di testo questo editor di testo dovrebbe applicare alcuni stili o colorazione su alcuni token (parole chiave) per evidenziarlo e renderlo evidente ,,, il il problema è che ho provato molto duramente, ma ottengo lo stesso risultato che è quando l'utente inserisce una delle parole chiave nell'intero testo dopo che quella parola chiave è stata disegnata! immagina solo se digiti la parola chiave "string" in "C#" l'intero testo dopo che sarà colorato di blu.WPF RichTextBox Sintassi Evento di evidenziazione

Questo è stato il codice che ho usato:

static List<string> tags = new List<string>(); 
    static List<char> specials = new List<char>(); 
    static string text; 
    #region ctor 
    static MainWindow() 
    { 
     string[] specialWords = { "string", "char", "null" };    
     tags = new List<string>(specialWords);  
     // We also want to know all possible delimiters so adding this stuff.  
     char[] chrs = { 
      '.', 
      ')', 
      '(', 
      '[', 
      ']', 
      '>', 
      '<', 
      ':', 
      ';', 
      '\n', 
      '\t', 
      '\r' 
     }; 
     specials = new List<char>(chrs); 
    } 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 
     #endregion 
    //Now I should check statically if the string I passed is legal and constants in my dictionary 
    public static bool IsKnownTag(string tag) 
    { 
     return tags.Exists(delegate(string s) { return s.ToLower().Equals(tag.ToLower()); }); 
    }    
    private static bool GetSpecials(char i) 
    { 
     foreach (var item in specials) 
     { 
      if (item.Equals(i)) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 
    // Wow. Great. Now I should separate words, that equals to my tags. For this propose we'll create new internal structure named Tag. This will help us to save words and its' positions. 
    new struct Tag 
    { 
     public TextPointer StartPosition; 
     public TextPointer EndPosition; 
     public string Word;  
    }    
    internal void CheckWordsInRun(Run theRun){ 
     //How, let's go through our text and save all tags we have to save.    
     int sIndex = 0; 
     int eIndex = 0; 
     List<Tag> m_tags = new List<Tag>(); 
     for (int i = 0; i < text.Length; i++) 
     { 
      if (Char.IsWhiteSpace(text[i]) | GetSpecials(text[i])) 
      { 
       if (i > 0 && !(Char.IsWhiteSpace(text[i - 1]) | GetSpecials(text[i - 1]))) 
       { 
        eIndex = i - 1; 
        string word = text.Substring(sIndex, eIndex - sIndex + 1);  
        if (IsKnownTag(word)) 
        { 
         Tag t = new Tag(); 
         t.StartPosition = theRun.ContentStart.GetPositionAtOffset(sIndex, LogicalDirection.Forward); 
         t.EndPosition = theRun.ContentStart.GetPositionAtOffset(eIndex + 1, LogicalDirection.Backward); 
         t.Word = word; 
         m_tags.Add(t); 
        } 
       } 
       sIndex = i + 1; 
      } 
     } 
     //How this works. But wait. If the word is last word in my text I'll never hightlight it, due I'm looking for separators. Let's add some fix for this case 
     string lastWord = text.Substring(sIndex, text.Length - sIndex); 
     if (IsKnownTag(lastWord)) 
     { 
      Tag t = new Tag(); 
      t.StartPosition = theRun.ContentStart.GetPositionAtOffset(sIndex, LogicalDirection.Forward); 
      t.EndPosition = theRun.ContentStart.GetPositionAtOffset(eIndex + 1, LogicalDirection.Backward); 
      t.Word = lastWord; 
      m_tags.Add(t); 
     } 
     //How I have all my words and its' positions in list. Let's color it! Dont forget to unsubscribe! text styling fires TextChanged event. 
     txtStatus.TextChanged -= txtStatus_TextChanged; 
     for (int i = 0; i < m_tags.Count; i++) 
     { 
      try 
      { 
       TextRange range = new TextRange(m_tags[i].StartPosition, m_tags[i].EndPosition); 
       range.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Blue)); 
       range.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold); 
      } 
      catch { } 
     } 
     m_tags.Clear(); 
     txtStatus.TextChanged += txtStatus_TextChanged; 
    } 

e qui è il testo cambiato gestore di eventi

private void txtStatus_TextChanged(object sender, TextChangedEventArgs e) 
    {   
     if (txtStatus.Document == null) 
      return; 
     TextRange documentRange = new TextRange(txtStatus.Document.ContentStart, txtStatus.Document.ContentEnd); 
     //documentRange.ClearAllProperties(); 
     text = documentRange.Text; 
     //Now let's create navigator to go though the text and hightlight it 
     TextPointer navigator = txtStatus.Document.ContentStart; 
     while (navigator.CompareTo(txtStatus.Document.ContentEnd) < 0) 
     { 
      TextPointerContext context = navigator.GetPointerContext(LogicalDirection.Backward); 
      if (context == TextPointerContext.ElementStart && navigator.Parent is Run) 
      { 
       CheckWordsInRun((Run)navigator.Parent); 
      } 
      navigator = navigator.GetNextContextPosition(LogicalDirection.Forward); 
     } 
    } 

Tutto il consiglio o la mano sarà molto apprezzato, , Grazie in anticipo.

risposta

6

È necessario evidenziare le parole chiave fino a quando tutto il testo viene analizzato, evidenziando le parole chiave in ogni Run interesserà la chiamata a navigator.GetNextContextPosition, causando errori imprevisti come l'esecuzione ripetuta di eventi di testo.

E dopo aver evidenziato una parola chiave, il testo digitato dopo quella parola chiave INERZIA lo stile di quella parola chiave. Una soluzione alternativa è chiamare ClearAllProperties sull'intero testo prima di accendere le parole chiave.

Di seguito è il metodo aggiornato txtStatus_TextChanged e CheckWordsInRun.

List<Tag> m_tags = new List<Tag>(); 
internal void CheckWordsInRun(Run theRun) //do not hightlight keywords in this method 
{ 
    //How, let's go through our text and save all tags we have to save.    
    int sIndex = 0; 
    int eIndex = 0; 

    for (int i = 0; i < text.Length; i++) 
    { 
     if (Char.IsWhiteSpace(text[i]) | GetSpecials(text[i])) 
     { 
      if (i > 0 && !(Char.IsWhiteSpace(text[i - 1]) | GetSpecials(text[i - 1]))) 
      { 
       eIndex = i - 1; 
       string word = text.Substring(sIndex, eIndex - sIndex + 1); 
       if (IsKnownTag(word)) 
       { 
        Tag t = new Tag(); 
        t.StartPosition = theRun.ContentStart.GetPositionAtOffset(sIndex, LogicalDirection.Forward); 
        t.EndPosition = theRun.ContentStart.GetPositionAtOffset(eIndex + 1, LogicalDirection.Backward); 
        t.Word = word; 
        m_tags.Add(t); 
       } 
      } 
      sIndex = i + 1; 
     } 
    } 
    //How this works. But wait. If the word is last word in my text I'll never hightlight it, due I'm looking for separators. Let's add some fix for this case 
    string lastWord = text.Substring(sIndex, text.Length - sIndex); 
    if (IsKnownTag(lastWord)) 
    { 
     Tag t = new Tag(); 
     t.StartPosition = theRun.ContentStart.GetPositionAtOffset(sIndex, LogicalDirection.Forward); 
     t.EndPosition = theRun.ContentStart.GetPositionAtOffset(text.Length, LogicalDirection.Backward); //fix 1 
     t.Word = lastWord; 
     m_tags.Add(t); 
    } 
} 

private void txtStatus_TextChanged(object sender, TextChangedEventArgs e) 
{ 
    if (txtStatus.Document == null) 
     return; 
    txtStatus.TextChanged -= txtStatus_TextChanged; 

    m_tags.Clear(); 

    //first clear all the formats 
    TextRange documentRange = new TextRange(txtStatus.Document.ContentStart, txtStatus.Document.ContentEnd); 
    documentRange.ClearAllProperties(); 
    //text = documentRange.Text; //fix 2 

    //Now let's create navigator to go though the text, find all the keywords but do not hightlight 
    TextPointer navigator = txtStatus.Document.ContentStart; 
    while (navigator.CompareTo(txtStatus.Document.ContentEnd) < 0) 
    { 
     TextPointerContext context = navigator.GetPointerContext(LogicalDirection.Backward); 
     if (context == TextPointerContext.ElementStart && navigator.Parent is Run) 
     { 
      text = ((Run)navigator.Parent).Text; //fix 2 
           if (text != "") 
       CheckWordsInRun((Run)navigator.Parent); 
     } 
     navigator = navigator.GetNextContextPosition(LogicalDirection.Forward); 
    } 

    //only after all keywords are found, then we highlight them 
    for (int i = 0; i < m_tags.Count; i++) 
    { 
     try 
     { 
      TextRange range = new TextRange(m_tags[i].StartPosition, m_tags[i].EndPosition); 
      range.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Blue)); 
      range.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold); 
     } 
     catch { } 
    } 
    txtStatus.TextChanged += txtStatus_TextChanged; 
} 
+1

yessssssssssssssssssss, vi ringrazio molto signore, dal mio cuore. apprezzo davvero la tua mano – a7madx7

+0

ho ancora un po 'di problema qui però, ogni volta che premo return (invio) e scrivo in una nuova riga il codice inizia a parole sbagliate hilight in posizioni sbagliate! – a7madx7

+2

@ Dr.Ahmed Oh, non ho provato con le nuove linee ... Bene, guarda la mia risposta aggiornata (etichettata come correzione 1 e correzione 2). – kennyzx

Problemi correlati