WPF RichTextBox语法突出显示问题

大家好我一直在研究一个带有文本编辑器的WPF应用程序这个文本编辑器应该应用一些样式或着色一些标记(关键字)来突出显示它并使其显而易见,,,问题是我非常努力但是我仍然得到相同的结果,即用户在关键字被设置样式后输入整个文本中的一个关键字! 试想一下,如果你在“C#”中键入“string”关键字,它之后的整个文字将会变成蓝色。

这是我使用的代码:

static List tags = new List(); static List specials = new List(); static string text; #region ctor static MainWindow() { string[] specialWords = { "string", "char", "null" }; tags = new List(specialWords); // We also want to know all possible delimiters so adding this stuff. char[] chrs = { '.', ')', '(', '[', ']', '>', '<', ':', ';', '\n', '\t', '\r' }; specials = new List(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 m_tags = new List(); for (int i = 0; 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); } } 

任何建议或手将非常感谢,提前感谢。

在解析所有文本之前,应突出显示关键字,突出显示每个Run的关键字将影响对navigator.GetNextContextPosition的调用,从而导致意外错误,例如重复触发textchanged事件。

在您突出显示关键字后,您在该关键字后面键入的文本将该关键字的样式设为INHERITS。 一种解决方法是在点亮关键字之前在整个文本上调用ClearAllProperties

下面是更新的txtStatus_TextChangedCheckWordsInRun方法。

 List m_tags = new List(); 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; }