用c#实现的语法高亮控件

  • A+
所属分类:C#

用c#实现的语法高亮控件 - snzy521的专栏 - CSDN博客
用c#实现了一个能够对vbscript,c#,j#,sql显示语法高亮的文本编辑控件。这里详细介绍一下它的原理。

该控件是从RichTextBox继承下来,以xml格式存储各种语言的关键字。然后重写RichTextBox的OnTextChanged方法,在该方法中对输入文本进行解析,并对关键字进行着色。源代码点击这里下载。

xml文件格式如下,这里仅以j#为例。caseSensitive代表该语言是否大小写敏感。当然,由于本人懒惰成性,关键字是从网上搜集别人整理好的,如有遗漏,概不负责:)

如果需要解析其他语言,请添加相应的xml文件,并修改枚举类型Languages以及Parser类的构造函数中的相应代码。已知bug:当两个词是由括号分割的时候,程序无法识别。比如Function foo(integer i),程序会把foo(integer当作一个词。当然这里有两个解决办法,一个是程序自动进行语法排版,在括号前后自动插入空格;另一个是对括号进行解析。也许以后有空的时候我会加上。


 private
 protected
 public
 namespace
 class
 var
 for
 if
 else
 while
 switch
 case
 using
 get
 return
 null
 void
 int
 string
 float
 this
 set
 new
 true
 false
 const
 static
 package
 function,
 internal
 extends
 super
 import
 default
 break
 try
 catch
 finally
 +
 -
 =

Parser类是负责对xml流进行解析,并包含一个方法来判断一个字符串是不是关键字。详细的代码和注释如下:
using System;
using System.Xml;
using System.IO;
using System.Collections;
using System.Reflection;
namespace SyntaxEditor
{
 ///

 /// Parser 的摘要说明。
 ///

 public class Parser
 {
  private  XmlDocument xd=null;
  private  ArrayList al=null;    //对xml流解析后,会把每一个关键字字符串放入这个容器中
  private bool caseSensitive=false;    //记录当前语言大小写敏感否
  internal Parser(SyntaxEditor.Languages language)    //构造函数接受一个枚举变量
  {
   //
   // TODO: 在此处添加构造函数逻辑
   //

Assembly asm = Assembly.GetExecutingAssembly();
   string filename="";
   switch(language)    //取得xml文件名
   {
    case SyntaxEditor.Languages.CSHARP:
     filename="csharp.xml";
     break;
    case SyntaxEditor.Languages.JSHARP:
     filename="jsharp.xml";
     break;
    case SyntaxEditor.Languages.SQL:
     filename="sql.xml";
     break;
    case SyntaxEditor.Languages.VBSCRIPT:
     filename="vbscript.xml";
     break;
    default:
     break;
   }

Stream strm = asm.GetManifestResourceStream(asm.GetName().Name + "."+filename);    //取得xml流

//Reads the contents of the embedded file.
   StreamReader reader= new StreamReader(strm);    //下面的代码解析xml流

xd=new XmlDocument();
   xd.Load(reader);

al=new ArrayList();
   XmlElement root=xd.DocumentElement;

XmlNodeList xnl=root.SelectNodes("/definition/word");
   for(int i=0;i<xnl.Count;i++)
   {

al.Add(xnl[i].ChildNodes[0].Value);
   }

this.caseSensitive=bool.Parse(root.Attributes["caseSensitive"].Value);

}
  public bool IsKeyWord(string word)    //判断字符串是否为关键字
  {
   bool rtn=false;
   for(int i=0;i<al.Count;i++)
   {
    if(string.Compare(word,al[i].ToString(),!caseSensitive)==0)
    {
     rtn=true;
     break;
    }
   }
   return rtn;

}
 }
}
控件类代码如下。

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using HWND = System.IntPtr;
namespace SyntaxEditor
{
 ///

 /// UserControl1 的摘要说明。
 ///

 public class SyntaxEditor : System.Windows.Forms.RichTextBox
 {
  ///

  /// 必需的设计器变量。
  ///

  private System.ComponentModel.Container components = null;
//使用win32api:SendMessage来防止控件着色时的闪烁现象

** [DllImport("user32")] private static extern int SendMessage(HWND hwnd, int wMsg, int wParam, IntPtr lParam);

  private const int WM_SETREDRAW = 0xB;
  public SyntaxEditor()
  {
   // 该调用是 Windows.Forms 窗体设计器所必需的。
   InitializeComponent();
   base.WordWrap=false;
   // TODO: 在 InitComponent 调用后添加任何初始化
  }
  ///

  /// 清理所有正在使用的资源。
  ///

  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if( components != null )
     components.Dispose();
   }
   base.Dispose( disposing );
  }
  #region 组件设计器生成的代码
  ///

  /// 设计器支持所需的方法 - 不要使用代码编辑器
  /// 修改此方法的内容。
  ///

  private void InitializeComponent()
  {
   //
   // SyntaxEditor
   //
   this.Name = "SyntaxEditor";
  }
  #endregion
 //重写基类的OnTextChanged方法。为了提高效率,程序是对当前文本插入点所在行进行扫描,
//以空格为分割符,判断每个单词是否为关键字,并进行着色。
  
protected override void OnTextChanged(EventArgs e)
  {
   if(base.Text!="")
   {
    int selectStart=base.SelectionStart;
    int line=base.GetLineFromCharIndex(selectStart);
    string lineStr=base.Lines[line];
    int linestart=0;
    for(int i=0;i<line;i++)
    {
     linestart+=base.Lines[i].Length+1;
    }

SendMessage(base.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
    base.SelectionStart=linestart;
    base.SelectionLength=lineStr.Length;
    base.SelectionColor=Color.Black;
    base.SelectionStart=selectStart;
    base.SelectionLength=0;
    string[] words=lineStr.Split(new char[]{' '});
    Parser parser=new Parser(this.language);
    for(int i=0;i<words.Length;i++)
    {
     if(parser.IsKeyWord(words[i]))
     {

int length=0;
      for(int j=0;j<i;j++)
      {
       length+=words[j].Length;
      }
      length+=i;
      int index=lineStr.IndexOf(words[i],length);


      base.SelectionStart=linestart+index;
      base.SelectionLength=words[i].Length;
      base.SelectionColor=Color.Blue;
      base.SelectionStart=selectStart;
      base.SelectionLength=0;
      base.SelectionColor=Color.Black;
     }
    }
    SendMessage(base.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
    base.Refresh();
   }
   base.OnTextChanged (e);
  }**
  public new bool WordWrap
  {
   get{return base.WordWrap;}
  }
  public enum Languages
  {
   SQL,
   VBSCRIPT,
   CSHARP,
   JSHARP
  }

private Languages language=Languages.SQL;
  public Languages Language
  {
   get{return this.language;}
   set{this.language=value;}
  }
 }
}


  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin