自定义Windows窗体控件--CodeRichText

自定义Windows窗体控件--CodeRichText

该控件可以作为一个简易的代码编辑器,可以实现代码的高亮显示,代码行号等。

CodeRichText.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using HWND = System.IntPtr;

namespace CodeRichText
{
    public partial class CodeRichText : UserControl
    {
        private string[] keywords ={ };
        private string[] dividers ={ };

        public CodeRichText()
        {
            InitializeComponent();
            UpdateLineNo();
        }

        [DllImport("user32")]
        private static extern int SendMessage(HWND hwnd, int wMsg, int wParam, IntPtr lParam);
        private const int WM_SETREDRAW = 0xB;

        public string[] KeyWords
        {
            get { return keywords; }
            set 
            {
                keywords = value;
                ColorAllText();
            }
        }

        public string[] Dividers
        {
            get { return dividers; }
            set
            {
                dividers = value;
                ColorAllText();
            }
        }

        public string CodeText
        {
            get { return this.richTextBoxSourceCode.Text; }
            set { this.richTextBoxSourceCode.Text = value; }
        }

        public Font CodeFont
        {
            get { return this.richTextBoxSourceCode.Font; }
            set { this.richTextBoxSourceCode.Font = value; }
        }

        public void LoadFile(string path)
        {
            richTextBoxSourceCode.LoadFile(path,RichTextBoxStreamType.PlainText);
        }

        public void SaveFile(string path)
        {
            richTextBoxSourceCode.SaveFile(path,RichTextBoxStreamType.PlainText);
        }

        private void ColorAllText()
        {
            if (richTextBoxSourceCode.Text == string.Empty) return;
            for (int i = 0; i < richTextBoxSourceCode.Lines.Length;i++ )
                ColorCurrentText(i);
        }

        private void ColorCurrentText(int lineNum)
        {
            if (richTextBoxSourceCode.Text == string.Empty) return;

            string lineStr = richTextBoxSourceCode.Lines[lineNum];
            int selectStart = richTextBoxSourceCode.SelectionStart;
            int lineStart=0;
            for(int i=0;i<lineNum;i++)
                lineStart+=richTextBoxSourceCode.Lines[i].Length+1;

            SendMessage(richTextBoxSourceCode.Handle, WM_SETREDRAW, 0, IntPtr.Zero);

            richTextBoxSourceCode.SelectionStart = lineStart;
            richTextBoxSourceCode.SelectionLength = lineStr.Length;
            richTextBoxSourceCode.SelectionColor = Color.Black;
            richTextBoxSourceCode.SelectionStart = selectStart;
            richTextBoxSourceCode.SelectionLength = 0;
            richTextBoxSourceCode.SelectionColor = Color.Black;

            string[] words = lineStr.Split(dividers,StringSplitOptions.RemoveEmptyEntries);
            int lineIndex = 0;
            foreach (string word in words)
            {
                if (IsKeyWord(word))
                {
                    lineIndex = lineStr.IndexOf(word, lineIndex);
                    richTextBoxSourceCode.SelectionStart = lineStart + lineIndex;
                    richTextBoxSourceCode.SelectionLength = word.Length;
                    richTextBoxSourceCode.SelectionColor = Color.Blue;

                    richTextBoxSourceCode.SelectionStart = selectStart;
                    richTextBoxSourceCode.SelectionLength = 0;
                    richTextBoxSourceCode.SelectionColor = Color.Black;

                    lineIndex += word.Length + 1;
                }
                else if (IsNumber(word))
                {
                    lineIndex = lineStr.IndexOf(word, lineIndex);
                    richTextBoxSourceCode.SelectionStart = lineStart + lineIndex;
                    richTextBoxSourceCode.SelectionLength = word.Length;
                    richTextBoxSourceCode.SelectionColor = Color.Tomato;

                    richTextBoxSourceCode.SelectionStart = selectStart;
                    richTextBoxSourceCode.SelectionLength = 0;
                    richTextBoxSourceCode.SelectionColor = Color.Black;

                    lineIndex += word.Length + 1;
                }
            }

            SendMessage(richTextBoxSourceCode.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
            richTextBoxSourceCode.Refresh();
        }

        private bool IsKeyWord(string word)
        {
            foreach (string s in keywords)
            {
                if (string.Compare(word, s) == 0)
                    return true;
            }
            return false;
        }

        private bool IsNumber(string word)
        {
            foreach (char ch in word)
            {
                if (!(ch >= '0' && ch <= '9'))
                    return false;
            }
            return true;
        }

        private void richTextBoxSourceCode_TextChanged(object sender, EventArgs e)
        {
            if (richTextBoxSourceCode.Text == string.Empty) return;
            int lineNum = richTextBoxSourceCode.GetLineFromCharIndex(richTextBoxSourceCode.SelectionStart);
            UpdateLineNo();
            ColorCurrentText(lineNum);
        }

        private void UpdateLineNo()
        {
            SendMessage(richTextBoxLineNo.Handle, WM_SETREDRAW, 0, IntPtr.Zero);

            //get index of first visible char and number of first visible line
            Point pos = new Point(0, 0);
            int firstIndex = richTextBoxSourceCode.GetCharIndexFromPosition(pos);
            int firstLine = richTextBoxSourceCode.GetLineFromCharIndex(firstIndex);

            //get index of last visible char and number of last visible line
            pos.X = ClientRectangle.Width;
            pos.Y = ClientRectangle.Height;
            int lastIndex = richTextBoxSourceCode.GetCharIndexFromPosition(pos);
            int lastLine = richTextBoxSourceCode.GetLineFromCharIndex(lastIndex);

            //this is the point position of last visible char, use its Y value for calculating numberLabel size
            pos = richTextBoxSourceCode.GetPositionFromCharIndex(lastIndex);

            //finally, update line number
            StringBuilder lineNo = new StringBuilder();
            for (int i = firstLine; i <= lastLine + 1; i++)
            {
                lineNo.Append((i + 1).ToString() + "\n");
            }
            richTextBoxLineNo.Text = lineNo.ToString();

            SendMessage(richTextBoxLineNo.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
            richTextBoxLineNo.Refresh();
        }

        private void CodeRichText_Scroll(object sender, ScrollEventArgs e)
        {

        }

        private void richTextBoxSourceCode_VScroll(object sender, EventArgs e)
        {
            //move location of line number for amount of pixels caused by scrollbar
            int d = richTextBoxSourceCode.GetPositionFromCharIndex(0).Y % (richTextBoxSourceCode.Font.Height + 1);
            richTextBoxLineNo.Location = new Point(0, d);
            UpdateLineNo();
        }

        private void richTextBoxLineNo_Enter(object sender, EventArgs e)
        {
            richTextBoxSourceCode.Focus();
        }

        private void richTextBoxSourceCode_FontChanged(object sender, EventArgs e)
        {
            richTextBoxLineNo.Font = new Font(richTextBoxSourceCode.Font, FontStyle.Regular);
        }
    }
}

 
CodeRichText.Designer.cs

namespace  CodeRichText
{
    partial 
class  CodeRichText
    {
        
///   <summary>
        
///  必需的设计器变量。
        
///   </summary>
         private  System.ComponentModel.IContainer components  =   null ;

        
///   <summary>
        
///  清理所有正在使用的资源。
        
///   </summary>
        
///   <param name="disposing"> 如果应释放托管资源,为 true;否则为 false。 </param>
         protected   override   void  Dispose( bool  disposing)
        {
            
if  (disposing  &&  (components  !=   null ))
            {
                components.Dispose();
            }
            
base .Dispose(disposing);
        }

        
#region  组件设计器生成的代码

        
///   <summary>
        
///  设计器支持所需的方法 - 不要
        
///  使用代码编辑器修改此方法的内容。
        
///   </summary>
         private   void  InitializeComponent()
        {
            
this .richTextBoxLineNo  =   new  System.Windows.Forms.RichTextBox();
            
this .richTextBoxSourceCode  =   new  System.Windows.Forms.RichTextBox();
            
this .SuspendLayout();
            
//  
            
//  richTextBoxLineNo
            
//  
             this .richTextBoxLineNo.BackColor  =  System.Drawing.SystemColors.ControlLight;
            
this .richTextBoxLineNo.BorderStyle  =  System.Windows.Forms.BorderStyle.None;
            
this .richTextBoxLineNo.Cursor  =  System.Windows.Forms.Cursors.Arrow;
            
this .richTextBoxLineNo.Dock  =  System.Windows.Forms.DockStyle.Left;
            
this .richTextBoxLineNo.Font  =   new  System.Drawing.Font( " Courier New " , 10F);
            
this .richTextBoxLineNo.ForeColor  =  System.Drawing.SystemColors.GradientActiveCaption;
            
this .richTextBoxLineNo.Location  =   new  System.Drawing.Point( 0 0 );
            
this .richTextBoxLineNo.Name  =   " richTextBoxLineNo " ;
            
this .richTextBoxLineNo.ReadOnly  =   true ;
            
this .richTextBoxLineNo.ScrollBars  =  System.Windows.Forms.RichTextBoxScrollBars.None;
            
this .richTextBoxLineNo.Size  =   new  System.Drawing.Size( 41 408 );
            
this .richTextBoxLineNo.TabIndex  =   1 ;
            
this .richTextBoxLineNo.Text  =   "" ;
            
this .richTextBoxLineNo.Enter  +=   new  System.EventHandler( this .richTextBoxLineNo_Enter);
            
//  
            
//  richTextBoxSourceCode
            
//  
             this .richTextBoxSourceCode.BorderStyle  =  System.Windows.Forms.BorderStyle.None;
            
this .richTextBoxSourceCode.Dock  =  System.Windows.Forms.DockStyle.Fill;
            
this .richTextBoxSourceCode.Font  =   new  System.Drawing.Font( " Courier New " , 10F);
            
this .richTextBoxSourceCode.Location  =   new  System.Drawing.Point( 41 0 );
            
this .richTextBoxSourceCode.Name  =   " richTextBoxSourceCode " ;
            
this .richTextBoxSourceCode.Size  =   new  System.Drawing.Size( 639 408 );
            
this .richTextBoxSourceCode.TabIndex  =   0 ;
            
this .richTextBoxSourceCode.Text  =   "" ;
            
this .richTextBoxSourceCode.VScroll  +=   new  System.EventHandler( this .richTextBoxSourceCode_VScroll);
            
this .richTextBoxSourceCode.TextChanged  +=   new  System.EventHandler( this .richTextBoxSourceCode_TextChanged);
            
//  
            
//  CodeRichText
            
//  
             this .AutoScaleDimensions  =   new  System.Drawing.SizeF(6F, 12F);
            
this .AutoScaleMode  =  System.Windows.Forms.AutoScaleMode.Font;
            
this .Controls.Add( this .richTextBoxSourceCode);
            
this .Controls.Add( this .richTextBoxLineNo);
            
this .Name  =   " CodeRichText " ;
            
this .Size  =   new  System.Drawing.Size( 680 408 );
            
this .Scroll  +=   new  System.Windows.Forms.ScrollEventHandler( this .CodeRichText_Scroll);
            
this .ResumeLayout( false );

        }

        
#endregion

        
private  System.Windows.Forms.RichTextBox richTextBoxLineNo;
        
private  System.Windows.Forms.RichTextBox richTextBoxSourceCode;
    }
}

现在程序还有bug: 假设“wang”是关键字,某一行的内容为:hellowang  wang,则本应该在第二个“wnag”上高亮显示,但是结果在“hellowang”中的“wang”上高亮显示了。
运行后界面如下:

自定义Windows窗体控件--CodeRichText_第1张图片

你可能感兴趣的:(自定义Windows窗体控件--CodeRichText)