This last weekend I expirimented a little bit with extending the functionality of the RichTextBox control. Below you’ll find an example of a small class that enherits from the RichTextBox control and allows you to implement syntax highlighting (with the use of a couple Win32 API call to smooth over the process of course.) The code pretty much speaks for itself.

Public Class SyntaxRTB

Inherits System.Windows.Forms.RichTextBox Private Declare Function SendMessage Lib “user32” Alias “SendMessageA” _ (ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

Private Declare Function LockWindowUpdate Lib “user32” (ByVal hWnd As Integer) As Integer

</span> Private _SyntaxHighlight_CaseSensitive As Boolean = False

</span> Private Words As New DataTable

</span> ‘Contains Windows Messages for the SendMessage API call Private Enum EditMessages LineIndex = 187 LineFromChar = 201 GetFirstVisibleLine = 206 CharFromPos = 215 PosFromChar = 1062 End Enum

Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs) ColorVisibleLines() End Sub

Public Sub ColorRtb() Dim FirstVisibleChar As Integer Dim i As Integer = 0

   </span><span>While</span><span> i < </span><span>Me</span><span>.Lines.Length
      FirstVisibleChar = GetCharFromLineIndex(i)
      ColorLineNumber(i, FirstVisibleChar)
      i += 1  </span><span>      End</span><span> </span><span>While
</span><span>End</span><span> </span><span>Sub</span>

Public Sub ColorVisibleLines() Dim FirstLine As Integer = FirstVisibleLine() Dim LastLine As Integer = LastVisibleLine() Dim FirstVisibleChar As Integer

   </span><span>If</span><span> (FirstLine = 0) </span><span>And</span><span> (LastLine = 0) </span><span>Then
      </span><span>'If there is no text it will error, so exit the sub
      </span><span>Exit</span><span> </span><span>Sub
   </span><span>Else  </span><span>         While</span><span> FirstLine < LastLine
         FirstVisibleChar = GetCharFromLineIndex(FirstLine)
         ColorLineNumber(FirstLine, FirstVisibleChar)
         FirstLine += 1
      </span><span>End</span><span> </span><span>While
   </span><span>End</span><span> </span><span>If
 
</span><span>End</span><span> </span><span>Sub</span>

Public Sub ColorLineNumber(ByVal LineIndex As Integer, ByVal lStart As Integer) Dim i As Integer = 0 Dim Instance As Integer Dim LeadingChar, TrailingChar As String Dim SelectionAt As Integer = Me.SelectionStart Dim MyRow As DataRow Dim Line() As String, MyI As Integer, MyStr As String

   </span><span>' Lock the update
   </span><span>LockWindowUpdate(</span><span>Me</span><span>.Handle.ToInt32)
 
   MyI = lStart
 
   </span><span>If</span><span> CaseSensitive </span><span>Then
      </span><span>Line = Split(</span><span>Me</span><span>.Lines(LineIndex).ToString, " ")
   </span><span>Else
      </span><span>Line = Split(</span><span>Me</span><span>.Lines(LineIndex).ToLower, " ")
   </span><span>End</span><span> </span><span>If
 
   </span><span>For</span><span> </span><span>Each</span><span> MyStr </span><span>In</span><span> Line
      </span><span>Me</span><span>.SelectionStart = MyI  </span><span>         Me</span><span>.SelectionLength = MyStr.Length
 
      </span><span>If</span><span> Words.Rows.Contains(MyStr) </span><span>Then
         </span><span>MyRow = Words.Rows.Find(MyStr)
         </span><span>If</span><span> (</span><span>Not</span><span> CaseSensitive) </span><span>Or</span><span> (CaseSensitive </span><span>And</span><span> MyRow("Word") = MyStr) </span><span>Then
            </span><span>Me</span><span>.SelectionColor = Color.FromName(MyRow("Color"))
         </span><span>End</span><span> </span><span>If  </span><span>         Else
         </span><span>Me</span><span>.SelectionColor = Color.Black
      </span><span>End</span><span> </span><span>If
 
      </span><span>MyI += MyStr.Length + 1  </span><span>      Next  </span><span>
   ' Restore the selectionstart
   </span><span>Me</span><span>.SelectionStart = SelectionAt
   </span><span>Me</span><span>.SelectionLength = 0
   </span><span>Me</span><span>.SelectionColor = Color.Black
 
   </span><span>' Unlock the update
   </span><span>LockWindowUpdate(0)
</span><span>End</span><span> </span><span>Sub</span>

Public Function GetCharFromLineIndex(ByVal LineIndex As Integer) As Integer Return SendMessage(Me.Handle, EditMessages.LineIndex, LineIndex, 0) End Function

Public Function FirstVisibleLine() As Integer Return SendMessage(Me.Handle, EditMessages.GetFirstVisibleLine, 0, 0) End Function

Public Function LastVisibleLine() As Integer Dim LastLine As Integer = FirstVisibleLine() + (Me.Height / Me.Font.Height)

   </span><span>If</span><span> LastLine > </span><span>Me</span><span>.Lines.Length </span><span>Or</span><span> LastLine = 0 </span><span>Then
      </span><span>LastLine = </span><span>Me</span><span>.Lines.Length  </span><span>      End</span><span> </span><span>If
 
   </span><span>Return</span><span> LastLine
</span><span>End</span><span> </span><span>Function</span>

Public Sub New() Dim MyRow As DataRow Dim arrKeyWords() As String, strKW As String

   </span><span>Me</span><span>.AcceptsTab = </span><span>True
 
   </span><span>''Load all the keywords and the colors to make them 
   </span><span>Words.Columns.Add("Word")
   Words.PrimaryKey = </span><span>New</span><span> DataColumn() {Words.Columns(0)}
   Words.Columns.Add("Color")
 
   arrKeyWords = </span><span>New</span><span> </span><span>String</span><span>() {"select", "insert", "delete", _
      "truncate", "from", "where", "into", "inner", "update", _
      "outer", "on", "is", "declare", "set", "use", "values", "as", _
      "order", "by", "drop", "view", "go", "trigger", "cube", _
      "binary", "varbinary", "image", "char", "varchar", "text", _
      "datetime", "smalldatetime", "decimal", "numeric", "float", _
      "real", "bigint", "int", "smallint", "tinyint", "money", _
      "smallmoney", "bit", "cursor", "timestamp", "uniqueidentifier", _
      "sql_variant", "table", "nchar", "nvarchar", "ntext", "left", _
      "right", "like","and","all","in","null","join","not","or"}

</span> For Each strKW In arrKeyWords MyRow = Words.NewRow() MyRow(“Word”) = strKW MyRow(“Color”) = Color.LightCoral.Name Words.Rows.Add(MyRow) Next

</span><span>End</span><span> </span><span>Sub</span>

Public Property CaseSensitive() As Boolean Get Return _SyntaxHighlight_CaseSensitive End Get Set(ByVal Value As Boolean) _SyntaxHighlight_CaseSensitive = Value End Set End Property

End Class

Update July 8th, 2008: Here’s a link that shows a couple tips that may help in writing your own Syntax Highlighting RichTextBox control:

http://codebetter.com/blogs/patricksmacchia/archive/2008/07/07/some-richtextbox-tricks.aspx