Working with RichTextBox for WPF and Silverlight > Overriding Styles |
The Syntax Coloring section described how you can use C1TextRange objects to modify the style of parts of a document without moving the selection. In some cases, however, you may want to modify only the view, and not the document itself.
For example, the current selection is highlighted with different foreground and background colors. This style change does not belong to the document itself; it belongs to the view. Other examples are syntax coloring and as-you-type spell-checking.
The C1RichTextBox control supports these scenarios with the StyleOverrides property. This property contains a collection of objects that specify ranges and style modifications to be applied to the view only. This approach has two advantages over applying style modifications to C1TextRange objects as you did in the previous section:
The limitation of this approach is that the style changes cannot involve style elements that affect the document flow. You can use style overrides to change the background, foreground, and to underline parts of the document. But you cannot change the font size or style, for example, since that would affect the document flow.
Let us demonstrate the use of style overrides by modifying the previous syntax coloring example.
First, we need to declare a C1RangeStyleCollection object and add that to the control's StyleOverrides collection. Once that is done, any overrides added to our collection will be applied to the control. We will later populate the collection with the syntax-colored parts of the document.
Visual Basic |
Copy Code
|
---|---|
Private _rangeStyles As New C1RangeStyleCollection() Public Sub New() InitializeComponent() _rtb = New C1RichTextBox() LayoutRoot.Children.Add(_rtb) AddHandler _rtb.TextChanged, AddressOf tb_TextChanged _rtb.FontFamily = New FontFamily("Courier New") _rtb.FontSize = 16 _rtb.Text = GetStringResource("w3c.htm") ' Add our C1RangeStyleCollection to the control's ' StyleOverrides collection _rtb.StyleOverrides.Add(_rangeStyles) End Sub |
C# |
Copy Code
|
---|---|
C1RangeStyleCollection _rangeStyles = new C1RangeStyleCollection(); public MainPage() { InitializeComponent(); _rtb = new C1RichTextBox(); LayoutRoot.Children.Add(_rtb); _rtb.TextChanged += tb_TextChanged; _rtb.FontFamily = new FontFamily("Courier New"); _rtb.FontSize = 16; _rtb.Text = GetStringResource("w3c.htm"); // Add our C1RangeStyleCollection to the control's // StyleOverrides collection _rtb.StyleOverrides.Add(_rangeStyles); } |
Now, all we need to do is modify the UpdateSyntaxColoring method shown earlier and have it populate our collection of range styles (instead of applying the coloring to the document as we did before):
Visual Basic |
Copy Code
|
---|---|
' Perform syntax coloring using StyleOverrides collection ' (takes a fraction of a second to highlight the default document) Private Sub UpdateSyntaxColoring(ByVal rtb As C1RichTextBox) ' Initialize regular expression used to parse HTML String pattern = "</?(?<tagName>[a-zA-Z0-9_:\-]+)" + "(\s+(?<attName>[a-zA-Z0-9_:\-]+)" + (?<attValue>(\s*=\s*""(^"")+"")?))*\s*/?>" ' Initialize styles used to color the document Dim key As var = C1TextElement.ForegroundProperty Dim brDarkBlue As var = New C1TextElementStyle() brDarkBlue(key) = New SolidColorBrush(Color.FromArgb(255, 0, 0, 180)) Dim brDarkRed As var = New C1TextElementStyle() brDarkRed(key) = New SolidColorBrush(Color.FromArgb(255, 180, 0, 0)) Dim brLightRed As var = New C1TextElementStyle() brLightRed(key) = New SolidColorBrush(Colors.Red) ' Remove old coloring _rangeStyles.Clear() ' Highlight the matches Dim input As var = rtb.Text Dim m As Match For Each m In Regex.Matches(input,pattern) ' Select whole tag, make it dark blue Dim range As var = rtb.GetTextRange(m.Index,m.Length) _rangeStyles.Add(New C1RangeStyle(range,brDarkBlue)) ' Select tag name, make it dark red Dim tagName As var = m.Groups("tagName") range = rtb.GetTextRange(tagName.Index, tagName.Length) _rangeStyles.Add(New C1RangeStyle(range,brDarkRed)) ' Select attribute names, make them light red Dim attGroup As var = m.Groups("attName") If Not attGroup Is Nothing Then Dim att As Capture For Each att In attGroup.Captures range = rtb.GetTextRange(att.Index, att.Length) _rangeStyles.Add(New C1RangeStyle(range,brLightRed)) Next End If Next End Sub |
C# |
Copy Code
|
---|---|
// Perform syntax coloring using StyleOverrides collection // (takes a fraction of a second to highlight the default document) 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*=\s*""[^""]+"")?))*\s*/?>"; // Initialize styles used to color the document var key = C1TextElement.ForegroundProperty; var brDarkBlue = new C1TextElementStyle(); brDarkBlue[key] = new SolidColorBrush(Color.FromArgb(255, 0, 0, 180)); var brDarkRed = new C1TextElementStyle(); brDarkRed[key] = new SolidColorBrush(Color.FromArgb(255, 180, 0, 0)); var brLightRed = new C1TextElementStyle(); brLightRed[key] = new SolidColorBrush(Colors.Red); // Remove old coloring _rangeStyles.Clear(); // Highlight the matches var input = rtb.Text; foreach (Match m in Regex.Matches(input, pattern)) { // Select whole tag, make it dark blue var range = rtb.GetTextRange(m.Index, m.Length); _rangeStyles.Add(new C1RangeStyle(range, brDarkBlue)); // Select tag name, make it dark red var tagName = m.Groups["tagName"]; range = rtb.GetTextRange(tagName.Index, tagName.Length); _rangeStyles.Add(new C1RangeStyle(range, brDarkRed)); // Select attribute names, make them light red var attGroup = m.Groups["attName"]; if (attGroup != null) { foreach (Capture att in attGroup.Captures) { range = rtb.GetTextRange(att.Index, att.Length); _rangeStyles.Add(new C1RangeStyle(range, brLightRed)); } } } } |
The revised code is very similar to the original. Instead of creating brushes to color the document, it creates C1TextElementStyle objects that contain an override for the foreground property. The code starts by clearing the override collection, then uses a regular expression to locate each HTML tag in the document, and finally populates the overrides collection with C1RangeStyle objects that associate ranges with C1TextElementStyle objects.
If you run this new version of the code, you should notice the dramatic performance increase. The new version is thousands of times faster than the original.