In This Topic
The Understanding C1TextPointer section describes how you can use the Selection property to obtain a object that corresponds to the current selection, and how to use that object to inspect and apply custom formatting to parts of the document.
In some cases, however, you may want to inspect and apply formatting to ranges without selecting them. To do that using the Selection property, you would have to save the current selection, apply all the formatting, and then restore the original selection. Also, changing the selection may cause the document to scroll in order to keep the selection in view.
To handle these situations, the C1RichTextBox exposes a GetTextRange method. The GetTextRange method returns a C1TextRange object that may be used without affecting the current selection.
For example, you could use the GetTextRange method to add HTML syntax coloring to a C1RichTextBox. The first step is to detect any changes to the document. The changes will trigger the method that performs the actual syntax coloring. In the following section learn how to implement Syntax Coloring in RichTextBox .NET Framework and .NET versions.
The code below implements the Syntax coloring feature.
Visual Basic |
Copy Code
|
' Update syntax coloring on a timer
Private _updating As Boolean
Private _syntax As Storyboard
' Start the timer whenever the document changes
Private Sub tb_TextChanged(sender As Object, e As C1TextChangedEventArgs)
If Not _updating Then
' Create storyboard if it's still null
If _syntax Is Nothing Then
_syntax = New Storyboard()
AddHandler _syntax.Completed, AddressOf _syntax_Completed
_syntax.Duration = New Duration(TimeSpan.FromMilliseconds(1000))
End If
' Re-start storyboard
_syntax.[Stop]()
_syntax.Seek(TimeSpan.Zero)
_syntax.Begin()
End If
End Sub
' Timer elapsed, update syntax coloring
Private Sub _syntax_Completed(sender As Object, e As EventArgs)
_updating = True
UpdateSyntaxColoring(_rtb)
_updating = False
End Sub
|
C# |
Copy Code
|
// Update syntax coloring on a timer
bool _updating;
Storyboard _syntax;
// Start the timer whenever the document changes
void tb_TextChanged(object sender, C1TextChangedEventArgs e)
{
if (!_updating)
{
// Create storyboard if it's still null
if (_syntax == null)
{
_syntax = new Storyboard();
_syntax.Completed += _syntax_Completed;
_syntax.Duration = new Duration(TimeSpan.FromMilliseconds(1000));
}
// Re-start storyboard
_syntax.Stop();
_syntax.Seek(TimeSpan.Zero);
_syntax.Begin();
}
}
// Timer elapsed, update syntax coloring
void _syntax_Completed(object sender, EventArgs e)
{
_updating = true;
UpdateSyntaxColoring(_rtb);
_updating = false;
}
|
The code creates a timer that starts ticking whenever the user changes the document in any way. If the user changes the document while the timer is active, then the timer is reset. This prevents the code from updating the syntax coloring too often, while the user is typing quickly.
When the timer elapses, the code sets a flag to prevent the changes made while updating the syntax coloring from triggering the timer, then calls the UpdateSyntaxColoring method:
Visual Basic |
Copy Code
|
' Perform syntax coloring
Private Sub UpdateSyntaxColoring(rtb As C1RichTextBox)
' Initialize regular expression used to parse HTML
Dim pattern As String = "</?(?<tagName>[a-zA-Z0-9_:\-]+)" & "(\s+(?<attName>[a-zA-Z0-9_:\-]+)(?<attValue>(=""[^""]+"")?))*\s*/?>"
' Initialize brushes used to color the document
Dim brDarkBlue As Brush = New SolidColorBrush(Color.FromArgb(255, 0, 0, 180))
Dim brDarkRed As Brush = New SolidColorBrush(Color.FromArgb(255, 180, 0, 0))
Dim brLightRed As Brush = New SolidColorBrush(Colors.Red)
' Remove old coloring
Dim input = rtb.Text
Dim range = rtb.GetTextRange(0, input.Length)
range.Foreground = rtb.Foreground
' Highlight the matches
For Each m As Match In Regex.Matches(input, pattern)
' Select whole tag, make it dark blue
range = rtb.GetTextRange(m.Index, m.Length)
range.Foreground = brDarkBlue
' Select tag name, make it dark red
Dim tagName = m.Groups("tagName")
range = rtb.GetTextRange(tagName.Index, tagName.Length)
range.Foreground = brDarkRed
' Select attribute names, make them light red
Dim attGroup = m.Groups("attName")
If attGroup IsNot Nothing Then
Dim atts = attGroup.Captures
For i As Integer = 0 To atts.Count - 1
Dim att = atts(i)
range = rtb.GetTextRange(att.Index, att.Length)
range.Foreground = brLightRed
Next
End If
Next
End Sub
|
C# |
Copy Code
|
// Perform syntax coloring
void UpdateSyntaxColoring(C1RichTextBox rtb)
{
// Initialize regular expression used to parse HTML
string pattern =
@"</?(?<tagName>[a-zA-Z0-9_:\-]+)" +
@"(\s+(?<attName>[a-zA-Z0-9_:\-]+)(?<attValue>(=""[^""]+"")?))*\s*/?>";
// Initialize brushes used to color the document
Brush brDarkBlue = new SolidColorBrush(Color.FromArgb(255, 0, 0, 180));
Brush brDarkRed = new SolidColorBrush(Color.FromArgb(255, 180, 0, 0));
Brush brLightRed = new SolidColorBrush(Colors.Red);
// Remove old coloring
var input = rtb.Text;
var range = rtb.GetTextRange(0, input.Length);
range.Foreground = rtb.Foreground;
// Highlight the matches
foreach (Match m in Regex.Matches(input, pattern))
{
// Select whole tag, make it dark blue
range = rtb.GetTextRange(m.Index, m.Length);
range.Foreground = brDarkBlue;
// Select tag name, make it dark red
var tagName = m.Groups["tagName"];
range = rtb.GetTextRange(tagName.Index, tagName.Length);
range.Foreground = brDarkRed;
// Select attribute names, make them light red
var attGroup = m.Groups["attName"];
if (attGroup != null)
{
var atts = attGroup.Captures;
for (int i = 0; i < atts.Count; i++)
{
var att = atts[i];
range = rtb.GetTextRange(att.Index, att.Length);
range.Foreground = brLightRed;
}
}
}
}
|
The code starts by defining a regular expression pattern to parse the HTML. This is not the most efficient way to parse HTML, and the expression is not terribly easy to read or maintain. We don't recommend using regular expressions for parsing HTML except in sample code, where it may help keep the code compact and easy to understand.
The next step is to remove any old coloring left over. This is done by creating a range that spans the whole document and setting its Foreground property to match the Foreground of the C1RichTextBox control.
Next, the regular expression is used to parse the document. The code scans each match, creates a C1TextRange object, and sets the C1TextRange.Foreground property to the desired value. We use dark blue for the HTML tag, dark red for the tag name, and light red for the attribute names.
That's all the code that is required. The image below shows an HTML document viewed in the syntax-coloring C1RichTextBox we just created:

Test the application by typing or pasting some HTML text into the control. Notice that shortly after you stop typing, the new text is colored automatically.
A real application could optimize the syntax coloring process by detecting the type of text change and updating the coloring of small parts of the document. Also, it would detect additional elements such as style sheets and comments, and it probably would use a specialized parser instead of regular expressions.
The essential mechanism would be the same, however: detect ranges within the document, get C1TextRange objects, and apply the formatting.
The code below implements the Syntax coloring feature.
C# |
Copy Code
|
// Update syntax coloring on a timer
bool _updating;
Storyboard _syntax;
// Start the timer whenever the document changes
private void RichTextboxTextChanged(object sender, C1.WPF.RichTextBox.C1TextChangedEventArgs e)
{
if (!_updating)
{
// Create storyboard if it's still null
if (_syntax == null)
{
_syntax = new Storyboard();
_syntax.Completed += SyntaxCompleted;
_syntax.Duration = new Duration(TimeSpan.FromMilliseconds(1000));
}
// Re-start storyboard
_syntax.Stop();
_syntax.Seek(TimeSpan.Zero);
_syntax.Begin();
}
}
// Timer elapsed, update syntax coloring
private void SyntaxCompleted(object sender, EventArgs e)
{
_updating = true;
UpdateSyntaxColoring(richTextbox);
_updating = false;
}
|
The code creates a timer that starts ticking whenever the user changes the document in any way. If the user changes the document while the timer is active, then the timer is reset. This prevents the code from updating the syntax coloring too often, while the user is typing quickly.
When the timer elapses, the code sets a flag to prevent the changes made while updating the syntax coloring from triggering the timer, then calls the UpdateSyntaxColoring method:
C# |
Copy Code
|
// Perform syntax coloring
private void UpdateSyntaxColoring(C1RichTextBox richTextbox)
{
// Initialize regular expression used to parse HTML
string pattern =
@"</?(?<tagName>[a-zA-Z0-9_:\-]+)" +
@"(\s+(?<attName>[a-zA-Z0-9_:\-]+)(?<attValue>(=""[^""]+"")?))*\s*/?>";
// Initialize brushes used to color the document
Brush brDarkBlue = new SolidColorBrush(Color.FromArgb(255, 0, 0, 180));
Brush brDarkRed = new SolidColorBrush(Color.FromArgb(255, 180, 0, 0));
Brush brLightRed = new SolidColorBrush(Colors.Red);
// Remove old coloring
var input = richTextbox.Text;
var range = richTextbox.GetTextRange(0, input.Length);
range.Foreground = richTextbox.Foreground;
// Highlight the matches
foreach (Match m in Regex.Matches(input, pattern))
{
// Select whole tag, make it dark blue
range = richTextbox.GetTextRange(m.Index, m.Length);
range.Foreground = brDarkBlue;
// Select tag name, make it dark red
var tagName = m.Groups["tagName"];
range = richTextbox.GetTextRange(tagName.Index, tagName.Length);
range.Foreground = brDarkRed;
// Select attribute names, make them light red
var attGroup = m.Groups["attName"];
if (attGroup != null)
{
var atts = attGroup.Captures;
for (int i = 0; i < atts.Count; i++)
{
var att = atts[i];
range = richTextbox.GetTextRange(att.Index, att.Length);
range.Foreground = brLightRed;
}
}
}
|
The code starts by defining a regular expression pattern to parse the HTML. This is not the most efficient way to parse HTML, and the expression is not terribly easy to read or maintain. We don't recommend using regular expressions for parsing HTML except in sample code, where it may help keep the code compact and easy to understand.
The next step is to remove any old coloring left over. This is done by creating a range that spans the whole document and setting its Foreground property to match the Foreground of the C1RichTextBox control.
Next, the regular expression is used to parse the document. The code scans each match, creates a C1TextRange object, and sets the C1TextRange.Foreground property to the desired value. We use dark blue for the HTML tag, dark red for the tag name, and light red for the attribute names.
That's all the code that is required. The image below shows an HTML document viewed in the syntax-coloring C1RichTextBox we just created:

Test the application by typing or pasting some HTML text into the control. Notice that shortly after you stop typing, the new text is colored automatically.
A real application could optimize the syntax coloring process by detecting the type of text change and updating the coloring of small parts of the document. Also, it would detect additional elements such as style sheets and comments, and it probably would use a specialized parser instead of regular expressions.
The essential mechanism would be the same, however: detect ranges within the document, get C1TextRange objects, and apply the formatting.