2013-07-31 115 views
5

大家好我一直對具有該文本編輯器應採用一些造型或着色過一些標記文本編輯器中的WPF應用程序(關鍵字),選中它,使它明顯的,,,問題是我非常努力地嘗試,但我仍然得到相同的結果,這是當用戶輸入關鍵字之後的整個文本中的一個關鍵字的樣式!想象一下,如果你在「C#」中鍵入「string」關鍵字,那麼它的全部文本將會變成藍色。WPF RichTextBox的語法高亮問題

這是我使用的代碼:

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

這裏是文本改變事件處理程序

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

任何意見或手將不勝感激, , 提前致謝。

回答

6

您應該突出顯示關鍵字,直到解析所有文本,突出顯示每個Run中的關鍵字將影響對navigator.GetNextContextPosition的調用,從而導致意外錯誤,例如重複觸發textchanged事件。

你hightlight關鍵字後,你該關鍵字後鍵入的文本繼承關鍵字的風格。在您點亮關鍵字之前,一種解決方法是在整個文本上調用ClearAllProperties

下面是更新txtStatus_TextChangedCheckWordsInRun方法。

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,非常感謝先生,從我的心裏。我真的很感激你的手。 – a7madx7

+0

還是有一點問題這裏雖然,,每當我打回車(Enter),並在一個新的行寫代碼開始在錯誤位置,以高亮顯示錯誤的話! – a7madx7

+2

@ Dr.Ahmed哦,我沒有用新行測試......好吧,看看我更新的答案(標記爲修復1和修復2)。 – kennyzx