RichTextBox for WPF | ComponentOne
Working with WPF RichTextBox / Overriding Styles
In This Topic
    Overriding Styles
    In This Topic

    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.

    In the following section learn how to implement Overriding Styles in RichTextBox .NET and .NET Framework versions.

    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.

    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.

    C#
    Copy Code
    C1RangeStyleCollection _rangeStyles = new C1RangeStyleCollection();
    
    public OverridingStyles()
    {
        InitializeComponent();
        richTextbox.TextChanged += RichTextboxTextChanged;
        richTextbox.FontFamily = new FontFamily("Courier New");
        richTextbox.FontSize = 16;
        richTextbox.Text = "<html>\r\t<body>\r\t\t<p height=\"20\">This is sample html syntax colored by overriding style.</p>\r\t</body>\r</html>";
    
        // Add our C1RangeStyleCollection to the control's
        // StyleOverrides collection
        richTextbox.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):

    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*/?>";
    
        // 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.