VB .NET Notepad: Implementing Syntax Highlighting and Line Numbers
Creating a Notepad-like application in VB .NET is a great way to learn Windows Forms and text handling. Adding syntax highlighting and line numbers makes it far more useful for code editing. This article walks through a concise, practical implementation using Windows Forms (WinForms) and a RichTextBox control with minimal external dependencies.
Overview
- Goal: A simple Notepad with syntax highlighting for a chosen language (example: VB.NET keywords) and a live line-number gutter.
- Approach: Use a RichTextBox for editable text, a Panel/Label or a separate read-only RichTextBox for the line-number gutter, and a keyword-based highlighting routine that updates on text changes and caret moves.
- Assumptions: Targeting .NET Framework or .NET (Windows) with WinForms; familiarity with VB .NET and basic event handling.
Project setup
- Create a new Windows Forms App (VB .NET).
- Add controls to the main form:
- RichTextBox named
rtbEditor(Dock = Fill). - Panel named
pnlGutterdocked Left to host line numbers (Width ≈ 50). - (Optional) A read-only RichTextBox named
rtbGutterinsidepnlGutterfor easier synchronization.
- RichTextBox named
- Set
rtbEditor.AcceptsTab = True,rtbEditor.Fontto a monospaced font (e.g., Consolas).
Line numbers: design and sync
Method: Use a read-only RichTextBox (rtbGutter) aligned with rtbEditor so scrolling and line wrapping appear consistent.
Key steps:
- Keep
rtbGutterread-only, same Font asrtbEditor, BackColor slightly different, BorderStyle = None. - Update gutter text whenever
rtbEditorcontent or scroll position changes.
Core routine (conceptual VB .NET code):
vb
’ Call this on Form Load and whenever text or layout changes Private Sub UpdateLineNumbers()Dim lines As Integer = rtbEditor.Lines.LengthDim sb As New System.Text.StringBuilder() For i As Integer = 1 To lines sb.AppendLine(i.ToString()) Next rtbGutter.Text = sb.ToString()End Sub
Sync scrolling:
- Handle
rtbEditor.VScroll(no built-in event; use Win32 message or a timer) orrtbEditor.SelectionChangedto align the gutter’s first visible line. - Simpler approach: set
rtbGutter.SelectionStart = rtbEditor.GetCharIndexFromPosition(New Point(0,0))and callrtbGutter.ScrollToCaret()to match vertical position.
Example helper to scroll gutter (simplified):
vb
Private Sub SyncGutterScroll() TryDim index As Integer = rtbEditor.GetCharIndexFromPosition(New Point(0, 0)) rtbGutter.SelectionStart = index rtbGutter.ScrollToCaret() Catch ex As Exception ' ignore End TryEnd Sub
Call
UpdateLineNumbers()andSyncGutterScroll()from:
rtbEditor.TextChangedrtbEditor.SelectionChanged- Form Resize
Performance tip: For large documents, avoid rebuilding the entire gutter on every keystroke. Use a short debounce timer (e.g., 100–200 ms) to batch updates.
Syntax highlighting: keyword-based approach
We’ll implement a fast, simple highlighter that colors VB .NET keywords and comments. This is not a full lexer but works well for small-to-medium files.
Design decisions:
- Use RichTextBox’s selection-based formatting (fast enough for moderate sizes).
- Preserve user selection and scroll position while applying formatting.
- Use Regex to locate tokens: keywords, comments, strings.
Example keywords list (partial):
vb
Dim keywords As String() = {“Module”,“Sub”,“Function”,“Dim”,“As”,“If”,“Then”,“Else”,“End”,“For”,“Next”,“While”,“Return”,“Public”,“Private”,“Class”,“New”}
Highlighting routine (conceptual):
vb
Private Sub HighlightSyntax() ‘ Remember selection and scrollDim selStart = rtbEditor.SelectionStart Dim selLength = rtbEditor.SelectionLength Dim viewportIndex = rtbEditor.GetCharIndexFromPosition(New Point(1,1)) ' Disable redrawing for smoother visual update SendMessage(rtbEditor.Handle, WM_SETREDRAW, False, 0) ' Reset all text color to default rtbEditor.SelectAll() rtbEditor.SelectionColor = Color.Black ' Highlight comments (single-line starting with ') Dim commentPattern As String = "'.*$" For Each m As Match In Regex.Matches(rtbEditor.Text, commentPattern, RegexOptions.Multiline) rtbEditor.Select(m.Index, m.Length) rtbEditor.SelectionColor = Color.Green Next ' Highlight strings Dim stringPattern As String = """([^""]|"""")*""" For Each m As Match In Regex.Matches(rtbEditor.Text, stringPattern) rtbEditor.Select(m.Index, m.Length) rtbEditor.SelectionColor = Color.Brown Next ' Highlight keywords (word boundaries) For Each kw As String In keywords Dim pattern As String = "" & Regex.Escape(kw) & "" For Each m As Match In Regex.Matches(rtbEditor.Text, pattern, RegexOptions.IgnoreCase) rtbEditor.Select(m.Index, m.Length) rtbEditor.SelectionColor = Color.Blue Next Next ' Restore selection and redraw rtbEditor.Select(selStart, selLength) SendMessage(rtbEditor.Handle, WM_SETREDRAW, True, 0) rtbEditor.Invalidate() ' Restore viewport rtbEditor.SelectionStart = viewportIndex rtbEditor.ScrollToCaret()End Sub
Notes:
- WMSETREDRAW is used to prevent flicker during formatting. Import via:
vb
_ Private Shared Function SendMessage(hWnd As IntPtr, wMsg As Integer, wParam As Boolean, lParam As Integer) As Integer End Function Private Const WM_SETREDRAW As Integer = 11
- Preserve user selection so typing isn’t disrupted.
Performance strategies:
- Highlight only visible text range instead of entire document for large files. Use GetCharIndexFromPosition and measure visible lines.
- Use a background worker or Task to compute token positions, then marshal formatting back to UI thread.
- Cache regex matches when possible; re-run only on changed lines.
Handling editing and caret movement
- Trigger highlighting on
TextChangedwith debounce, and minor updates onKeyUpfor quick feedback. - Update line numbers and gutter sync on the same events.
- For multi-threaded highlighting, ensure all RichTextBox updates run on the UI thread (Invoke/BeginInvoke).
Optional enhancements
- Add brace matching (highlight matching parentheses).
- Implement auto-indentation on Enter key.
- Add customizable themes (colors, font) via settings.
- Use a third-party text editor control (e.g., ScintillaNET) for robust editing features if you need high performance and full language support.
Example wiring (events)
- rtbEditor.TextChanged -> Start debounce timer -> HighlightSyntax + UpdateLineNumbers + SyncGutterScroll
- rtbEditor.SelectionChanged -> SyncGutterScroll
- Form.Resize -> UpdateLineNumbers + SyncGutterScroll
Final notes
This approach gives a lightweight VB .NET Notepad with basic syntax highlighting and line numbers using built-in controls. For production-grade editors with large files and advanced language features, prefer specialized controls like ScintillaNET or AvalonEdit (WPF) which provide built-in lexing, folding, and much better performance.
If you want, I can provide a complete sample project (full VB .NET code files) implementing the routines above.
Leave a Reply