Thursday, June 24, 2004

In this blog, I'll show how you can a implement a control to colorizes XML in a simple and effective way. I needed to display XML in a control, however, displaying it in "black and white" made it very depressing.  I have 3 objectives: simplicity, simplicity and simplicity.You can think of this as a traditional Microsoft interview enigma. So let's enumerate what we need and what we want (and what we want to avoid). 

What we want: colors!
What we don't want: manipulate the XML Dom, in other words: let's be lazy.
What we have: it's time to dig into the FCL classes and see what we could use 

  • RichTextBox: this control seems to be the perfect match for our "coloring" purposes,
  • XmlTextWriter: this class is a forward only, non-cached Xml writer. This class provides a rich set of method that output elements, attributes, etc...

Implementation

At this point, you must have an idea of the way we are going to acheive colors... the tools are here, we just need to inject the color at the right spot (like in a toothpaste, the color lines come right at the end). In fact, we have 3 tasks to acheive:

1) RichTextBoxWriter:

A TextWriter-derived class that writes to a RichTextBox. The writer keeps a current Color and Font that is apply to each chunk of string appended. This task is pretty straightforward, basically you need to overload 3 Write methods.

public class RichTextBoxWriter : TextWriter
{
    private RichTextBox textBox;
    private Color currentColor=Color.Black;
    private Font currentFont = new Font("Tahoma",8.25f);

    ...

    public override void Write(char value)
    {
        this.TextBox.SelectedText = value.ToString(this.FormatProvider);
    }
    public override void Write(char[] buffer)
    {
        if (buffer!=null)
        {
            this.TextBox.SelectedText = new String(buffer).ToString(this.FormatProvider);
            // if buffer = '\n\r', font and color is reseted
            this.TextBox.SelectionColor=this.CurrentColor;
            this.TextBox.SelectionFont=this.CurrentFont;
        }
    }
    public override void Write(string value)
    {
        this.TextBox.SelectedText = value.ToString(this.FormatProvider);
    }
}

Wow, that was short. Now to point 2.

2) XmlRichTextWriter:

This class, which inherits from XmlTextWriter, injects color on some "startegic" methods. In order to store the colors, we create XmlRichTextBox, which inherits from RichTextBox and contains a rich set of customizable colors and fonts for the Xml rendering. This class will be used by the XmlRichTextBoxWriter:

public class XmlRichTextBoxWriter : XmlTextWriter
{
    private XmlRichTextBox theme; // contains all the colors and fonts

    public XmlRichTextBoxWriter(XmlRichTextBox tb)
    :base(tb.Writer)
    {
        this.theme=tb;
    }

    public override void WriteStartDocument()
    {
        // setting color of the selected text
        this.theme.Writer.CurrentColor = this.theme.StartColor;
        this.theme.Writer.CurrentFont = this.theme.StartFont;
        // output data
        base.WriteStartDocument();
    }
    ...
}

4) XmlRichTextBox:

Now, that we have our writer, we just need to wire them up in the XmlRichTextBox and we are done.

And finally, the result: on the left, a XmlRichTextBox, on the left, how it looks like in the PropertyGrid. We have colooors!

Download it now....

posted on Thursday, June 24, 2004 11:08:00 AM UTC  #    Comments [6]
Tracked by:
"call of duty finest hour" (online) [Trackback]
"corriere espresso" (online) [Trackback]
Monday, June 06, 2005 5:53:51 PM UTC
You're too much man! I can't keep up.
Aaron A. Anderson
Monday, June 06, 2005 5:53:52 PM UTC
Download seems to be broken
Barry Gervin
Monday, June 06, 2005 5:53:52 PM UTC
Ooops... it's now on the <a title="MbUnit, Generating Unit Testing and Model Based Testing Framework for .NET Framework" href="http://mbunit.tigris.org" target="_blank">MbUnit</a> CVS, (Samples/Reflector.Helpers) or you can directly get it here:
<br>
<br><a target="_new" href="http://mbunit.tigris.org/source/browse/mbunit/src/Samples/Reflector.Helpers/XmlRichTextBox.cs?rev=1.1&amp;content-type=text/vnd.viewcvs-markup">http://mbunit.tigris.org/source/browse/mbunit/src/Samples/Reflector.Helpers/XmlRichTextBox.cs?rev=1.1&amp;content-type=text/vnd.viewcvs-markup</a>
Jonathan de Halleux
Monday, June 06, 2005 5:53:53 PM UTC
This is excellent, however what about updating whilst you type??? How would you achieve that? Been trying for ages...
Lee Keable
Monday, June 06, 2005 5:53:53 PM UTC
Great idea and works quite well for a small amount of data (about 2 pages worth). RichTextBox must have a ton of intenal events firing because the rendering time appears to be almost exponential to the data size! Suspending paint events appears to only give a marginal perf boost...
Michael Bouck
Monday, June 06, 2005 5:53:54 PM UTC
In fact, I did not test it with large xml files. If you have a fix that can speed it up, don't hesitate to feedback :)
Jonathan de Halleux
Comments are closed.