Saturday, August 20, 2011

Opening a WPF window from a C++ application.

Hello All,

I was recently requested to show a WPF UI from legacy C++ code. I thought that this is a quite common task and that I would be able to find ample resources about it on the internet but I found only general guidance with lots of missing details that assume you are a C++ developer wanting to use WPF while I am a WPF developer wanting to reuse legacy C++ code. I hope this short guide will help my readers to accomplish this quite simple task.


My implementation is generic and contains three parts:
  1. The C++ COM interface.
  2. The WPF application (i.e. the client).
  3. The C++ application (i.e. the host).
The goal: Open a simple dialog that will show "Hello World" in a WPF window from my C++ application. To achieve this goal I will be using COM interoperability (but don't worry, if you have no clue in COM you can still use this method. I will explain the parts that you need).

Creating the COM interface
Fire up your Visual Studio (I will be using Visual Studio 2010 Ultimate) and create a new ATL Project (Other languages, C++ category). A wizard will pop up just press Finish.
You will see two projects were created, one with the name you selected (I selected TheInterface so I will run with this name) and the other with the name you selected and PS suffix.
  • Delete the project with the PS suffix (in my case TheInterfacePS).
  • Delete the Generated Files folder from your project.
  • Delete ReadMe.txt (unless you really like it).
  • In the Header Files folder leave only Resource.h,  StdAfx.h and dllmain.h (delete the rest).
  • Open TheInterface.cpp file (if you selected a different name it will be <your name>.cpp) and add the line:
         #include "TheInterface_i.c"
      right after the line:
      #include "TheInterface_i.h"
      but before the line:
      #include "dllmain.h"


Build the project. At this point the build should pass.
Your solution will look something like this.
Now we will define our COM interface. Open the idl file (TheInterface.idl). You will see the library that was defined for you by the wizard. We will add our interface to that library. The syntax is simple and similar to C#. In square braces you define something like attributes and then the interface itself. Each COM interface must be assigned a GUID. Inside the library definition (in the block surrounded by the curly braces add the following definition (at the end)



   [
        uuid(20F0BD1B-4B00-4a1f-B600-420631C40CD8),
helpstring("IShowDialog Interface"),
    ]
Note that you shouldn't use the GUID from my example! 
To create a new GUID use the Create GUID tool found in the Tools menu of Visual Studio. In the Create GUID tool select registry format (4) and copy the GUID. Don't forget to remove the curly braces after you paste it.
Create GUID tool.


(The helpstring is not mandatory but it will show in several places that will help you later)


Now for the interface itself:

    interface IShowDialog : IUnknown
{
     [id(1),helpstring("Show the dialog")] HRESULT ShowDialog([in]BSTR bstrCaption);
    };




The IUnknown is the base interface of COM interfaces so we inherit from it. We create one method and give it the id of 1 (the helpstring is again not mandatory. Our method returns HRESULT, is called ShowDialog and accepts one parameter of type BSTR (which in the string type of COM). 
Your idl file should look something like this:

import "oaidl.idl";
import "ocidl.idl";
 
[
	uuid(DB9255B8-4D42-42D2-8C81-6734E52EEDB3),
	version(1.0),
]
library TheInterfaceLib
{
	importlib("stdole2.tlb");
	
	[
      uuid(73756BB5-41B1-4383-B899-B4EB4AE0A38A),
	  helpstring("IShowDialog Interface"),
    ]
    interface IShowDialog : IUnknown
	{
     [id(1),helpstring("Show the dialog")] HRESULT ShowDialog([in]BSTR bstrCaption);
    };
 
};

Now open the properties of your project and go to the MIDL-> Output category. There are two items to notice here:
  1. Header file - This is the file you will use in your C++ project to use the interface definition.
  2. Type library - This is the file we are going to use for our C# project.
The next and final thing to do is to create an interop dll that we can easily use in our C# project. Open the properties of your project again and go to Build Events -> Post-build events. Edit the Command line and write there:
tlbimp.exe $(IntDir)TheInterface.tlb /namespace:MyNamespace /out:"$(IntDir)Interop.TheInterface.dll"
The tlbimp tool (comes with Visual Studio) and it will transform your tlb file into a dll you can reference in your C# project. One thing to notice is the namespace parameter where you define your namespace (as in any .NET dll).
Now we have all the needed tools to communicate between the C++ and the C# projects so lets create them.
Creating the C# project
Add to your project a C# WPF Application (I call it TheDialog). First we create a class that will implement the interface we declared earlier. First I reference the interop dll we created ealier - Interop.TheInterface.dll and create a class called DialogShower that will show the dialog.
At this point we remember that we will create this class from the C++ application and therefore we must mark it with some attributes to make it visible by COM. The attributes are:
  1. [ComVisible(true)] - So that the class will be registered to COM.
  2. [Guid("48CCE666-E6C4-464C-94D3-83148A88A6D5")] - Because every COM objects needs a GUID.
  3. [ClassInterface(ClassInterfaceType.None)] - Means we are implementing our own interface.
  4. [ProgId("WPFMessageDialog")] - This is the "secret keyword" we can use to create this object in C++ code (you will see later).
In my class I will simply show the default window that will contain a label with the provided message (note that the interface implementation contains a string parameter converted from BSTR).
Since the project is an application you can run it for a small test.
Creating the C++ project
Now for the last part, creating the C++ project. We add a C++ Win32 Console application to our solution called TheApplication. In the wizard click next and then select ATL checkbox (in "Add common header files for:").
In your main file you must add include to TheInterface_i.h file created in the first part and to comutil.h which comes by default.
The code in my main method is:
	USES_CONVERSION;  //Needed to convert from regular "" strings to BSTR
	CComPtr<IShowDialog> dialog;
	if (CoInitializeEx(NULL,COINIT_APARTMENTTHREADED) != S_OK)	 //Needed to use any COM call in your application
		return -1;
 
    HRESULT res = dialog.CoCreateInstance(L"WPFMessageWindow", NULL, CLSCTX_INPROC_SERVER); //Create the instance of our object through COM
	if (FAILED(res))
		return -1;	
	BSTR message = SysAllocString(L"Hello World"); //Convert a regular string to BSTR (COM string)
	dialog->ShowDialog(message); // Show the dialog
	SysFreeString(message); // Free the created string
	CoUninitialize(); //Uninitialized COM
	return 0;
Comments are in the body.
And the result is:

A few needed things to make things work correctly:
  • You must have access to the TheInterface_i.h file from the main C++ application. I suggest configuring the MIDL section of that project to produce this file to some global location.
  • The same applies for the Interop.TheInterface.dll file. You might want to build it to some global bin dir.
  • Note that the WPF dll contains a COM object therefore you must register it within any system that will run your application. You cannot use regsvr32 to do that. Instead you must run the following command in the post build events of the WPF application: 
%windir%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe "$(TargetDir)$(TargetFileName)" /regfile:"$(TargetDir)$(TargetFileName).reg"
This will register the dll on your local machine and create a registry file 
that you will have to run on the deployment machine.
  • The exe file of the application and the dll/exe of the WPF dialog assembly must be in the same directory otherwise the COM object will not be created.
That's it for today. I hope you enjoyed the post. 
You can find all the related files on my SkyDrive here.
Thanks for reading,
Boris.

Saturday, August 6, 2011

A philosophical view on interview questions using BFS and DFS traversals

Hello All,

Today I want to talk about computer science riddles versus computer science problems especially during job interviews. I will start by saying I hate CS riddles, I don't understand why someone would give them in an interview and what it would show about both the interviewer and the interviewee. On the other hand I love CS problems which made me wonder what is the difference between the two. I thought long and hard about this question and decided that the main difference is that a CS riddle is usually solved using a very specific, usually unorthodox method which in many times is not directly related to the topic (or general area) of the question. On the other hand a CS problem can be solved in many ways which usually derive from well known practices in CS.


Anyway... My story starts one day when I wondered into the kitchen at work seeking a cup of tea. I saw one of my group mates interviewing some guy. At this point he left the room to let the interviewee deal with the question alone so I took the opportunity to ask what was the question. He said that he asked the interviewee to print a binary tree using a BFS traversal. This is after he already solved the same question using the DFS traversal. I responded that this is a nice warm-up question since the two methods differ only by the words Stack (for DFS) and Queue (for BFS) and other than that the algorithm is exactly the same. He said that the interviewee solved the DFS traversal using recursion so he may have to think. 
At this point I could leave the kitchen and concentrate on drinking my tea but I thought to myself... What is the difference between the recursive DFS and BFS methods?


Thinking further I realized that it is not that simple to implement a recursive BFS method because essentially the recursion uses a Stack while BFS uses a queue which are the opposite.
For the sake of this exercise I assume that a recursive method cannot use any loops of any kind and all the traversal must be done using the recursion.


I implemented a small tree class as follows:

  public class TreeNode
  {
    public int Data
    {
      get;
      set;
    }
 
    public TreeNode Left
    { get; set; }
 
    public TreeNode Right
    { get; set; }
 
    public TreeNode(int data)
    {
      Data = data;
    }
  }
 
  public class Tree
  {
    public TreeNode Root
    {
      get;
      set;
    }

First I will present the iterative DFS and BFS methods (just to prove my point that they differ in only that one word)
   internal void PrintDfs()
    {
      Console.Out.WriteLine("Printing tree using iterative DFS algorithm");
      Stack<TreeNode> nodes = new Stack<TreeNode>();
      nodes.Push(Root);
      while (nodes.Count > 0)
      {
        TreeNode tempNode = nodes.Pop();
        Console.Out.Write(string.Format("{0},", tempNode.Data));
        if (tempNode.Right != null)
          nodes.Push(tempNode.Right);
        if (tempNode.Left != null)
          nodes.Push(tempNode.Left);
      }
      Console.Out.WriteLine();
    }
 
    internal void PrintBfs()
    {
      Console.Out.WriteLine("Printing tree using iterative BFS algorithm");
      Queue<TreeNode> nodes = new Queue<TreeNode>();
      nodes.Enqueue(Root);
      while (nodes.Count > 0)
      {
        TreeNode tempNode = nodes.Dequeue();
        Console.Out.Write(string.Format("{0},", tempNode.Data));
        if (tempNode.Left != null)
          nodes.Enqueue(tempNode.Left);
        if (tempNode.Right != null)
          nodes.Enqueue(tempNode.Right);
      }
      Console.Out.WriteLine();
      
    }
Implementing DFS using recursion is trivial:
    private void PrintDfsRecursiveInternal(TreeNode node)
    {
        Console.Out.Write(string.Format("{0},", node.Data));
        if (node.Left != null)
          PrintDfsRecursiveInternal(node.Left);
        if (node.Right != null)
          PrintDfsRecursiveInternal(node.Right);
    }
 
    internal void PrintDfsRecursive()
    {
      Console.Out.WriteLine("Printing tree using recursive DFS algorithm");
      PrintDfsRecursiveInternal(Root);
      Console.Out.WriteLine();
    }
Now what about implementing BFS using recursion. Well, I read a bit online and I tend to believe that it is impossible to do it in O(1) extra space therefore I will show a solution with O(n) extra space. Before I present my solution I would like to note a solution I found online here:
BFS(Q)
{
  if (|Q| > 0)
     v <- Dequeue(Q)
     Traverse(v)
     foreach w in children(v)
        Enqueue(Q, w)    

     BFS(Q)
}

There is something very bad in this solution (and in fact all other solution I saw). Because the recursive call is at the end of the method the recursion level is O(n) while the recursion level of the DFS algorithm is only O(log(n)). Considering the fact that opening a stack frame is somewhat expensive, this makes a major difference.


My solution uses the regular DFS traversal but ignores the nodes from the DFS order and calculated the nodes from the BFS order passed by the queue to the recursive method.
 internal void PrintBfsRecursive()
    {
      Console.Out.WriteLine("Printing tree using recursive BFS algorithm");
      Queue<TreeNode> queue = new Queue<TreeNode>();
      queue.Enqueue(Root);
      PrintBfsRecursiveInternal(queue, Root);
      Console.Out.WriteLine();
    }
 
    private void PrintBfsRecursiveInternal(Queue<TreeNode> queue, TreeNode node)
    {
      if (queue.Count > 0)
      {
        TreeNode tempNode = queue.Dequeue();
        Console.Out.Write(string.Format("{0},", tempNode.Data));
        if (tempNode.Left != null)
          queue.Enqueue(tempNode.Left);
        if (tempNode.Right != null)
          queue.Enqueue(tempNode.Right);
      }
 
      if (node.Left != null)
        PrintBfsRecursiveInternal(queue,node.Left);
      if (node.Right != null)
        PrintBfsRecursiveInternal(queue, node.Right);
    }
As you can see I used the DFS traversal only as a counter for the iterative BFS algorithm but this saves me the exponential increase in stack size.

In any case, if you are interested in CS problems (not riddles) I suggest checking out this site: Project Euler (if you want to collaborate with me on this please email me)

Thanks for reading,
Boris.

Friday, July 29, 2011

Filtering TextBox

Hi All,


Today I want to present a nice control that I wrote called the Filtering TextBox (FTB for short). Consider the following case: You have a known (static) list of items, each item represents some sort of operation (the basic operation can be selecting this item but it is not mandatory) and you want to allow the user to see the entire list of items but also filter the shown items based on a text input from the user (similar to city selection in any maps site). Some extra features that my control allows:

  1. Categorizing items - Each item is assigned to a category and these categories are displayed in the list box (above the items).
  2. Disabling items - Each item may be disabled. It appears in the filtered list but the user cannot select it.
  3. Invisible items - Each item may be invisible to the user even if it corresponds to the input text.
  4. Hint Text - Each item may contain a hint text which will be displayed in a slightly grayed out text next to the item display text.
  5. Any class items - An item can be any class as long as it implements a predefined interface.


An example of how the Filtering TextBox works.

I will not show all the implementation details but describe a few interesting points.

There are two type of items in the list. A category and a selectable item. The user distributes items per categories by providing a property getter for the Category property. The control maps all items into the given categories automatically.

Each item added to the FTB must implement the IFilteringTextBoxItem interface and all items must be added in a single call to the Add method. All subsequent calls will simply remove all the previous items.

The SearchTextBox custom control is a simple TextBox with a background text added to it. I got the idea for the implementation from Kevin and his Bag of tricks. At first I thought I would use his control directly but I didn't like his implementation so I implemented my own.

The filter uses two search methods -
  1. Simple string "contains" (CIAI) for each word in the input TextBox.
  2. Something like CamelCase notation for words  (I saw this method was popular so I added it) i.e. you can type the first letters in the string you search.
You can download the full source code from my SkyDrive here. The code is as usual under the COPL (The Code Project Open License 1.02).

Feel free to leave comments.

Boris.

Saturday, July 23, 2011

On a sick leave

Hi All,


Due to sickness of myself and all the members of my family there was no post last week and no post this week.
I hope next week everyone feels better and I will have time to write my post.


Stay tuned,
Thanks,
Boris.

Friday, July 8, 2011

JIT/Compiler Optimization of Fibonacci calculation

[intermediate-high level]
Hi All,


Today I want to consider the following case:
In my application I want to use some Fibonacci numbers (this is just a hypothetical example :)). I want to see if I can make the JIT/C++ Compiler to put the actual number instead of calling the calculation method. I made two implementations of the calculation but I will show only one, recursive and horribly slow implementation (don't ever use it or even consider of using it!):

    static int FibonacciRecursive(int level)
    {
      if (level == 0)
        return 0;
      if (level == 1)
        return 1;
      return FibonacciRecursive(level - 1) + FibonacciRecursive(level - 2);
    }
And my code for the tests is:
    static void Main(string[] args)
    {
      Console.ReadLine();
      int result = FibonacciRecursive(45);
      Console.Out.WriteLine(result);
    }
I added the ReadLine so that I will have time to attach a debugger when I run the code. The 45th Fibonacci number, if you were wondering, is 1134903170 and not long after that it overflows int :).
I will save you the reading time and not try my code in debug mode. I will first run my code from Visual Studio by pressing "Run" and here is the result (I added comments in case your assembly is a little rusty):

;      int result = FibonacciRecursive(45);
00000022  mov         ecx,2Dh ;put 45 in the ecx register (this is how methods in .net expect their first argument)
00000027  call        dword ptr ds:[006C1F34h] ;call the FibonacciRecursive method 
0000002d  mov         dword ptr [ebp-0Ch],eax ;get the return value from eax register and put it in the "result" variable
00000030  mov         eax,dword ptr [ebp-0Ch] 
00000033  mov         dword ptr [ebp-8],eax 

As you can see there was no optimization in this case, in fact we can see the two lines 
0000002d  mov         dword ptr [ebp-0Ch],eax 
00000030  mov         eax,dword ptr [ebp-0Ch] 
Which copy the return value of the function (stored in eax) to the result variable and then copy it back to eax.

Now I will run the same code but attach the debugger at a later stage (after JIT generated the code) here is the result (again I added some comments):
00000013  mov         ecx,2Ch ;put 44 in ecx register
00000018  call        dword ptr ds:[001A37F8h] ;call the FibonacciRecursive method
0000001e  mov         esi,eax ;put the result in esi register
00000020  mov         ecx,2Bh ;put 43 in the ecx register
00000025  call        dword ptr ds:[001A37F8h] ;call the FibonacciRecursive method
0000002b  add         eax,esi ;add the results of the two calls into eax register

As you can see the code is much more optimized. Which means JIT generates different code if it sees a debugger attached so even when you compile in Release with optimization and run in VS you don't see the most optimized code. 
You can also see that the JIT compiler unwinded the recursion and put its code inline but again the JIT compiler called the method and did not generate the result directly as I wanted. If you are beginning to doubt this is at all possible, keep reading.

Now I will change the call to 
int result = FibonacciRecursive(1);
 and run it without VS. Here is the result:
00000019  mov         edx,1 
Just as we wanted! Instead of calling the method it simply put 1 as the result.
Lets try running it with 
int result = FibonacciRecursive(2);
The result is quite interesting:
00000013  mov         ecx,1 ;put 1 in the ecx register
00000018  call        dword ptr ds:[001937F8h] ;call FibonacciRecursive
0000001e  mov         esi,eax ;put the result in esi register
00000020  mov         ecx,0 ;put 0 in the ecx register
00000025  call        dword ptr ds:[001937F8h] ;call FibonacciRecursive
0000002b  add         eax,esi ;add the results of the two calls
This is really nice. Now we have two calls which are non recursive. This makes me wonder why it didn't run the same logic as it did in the previous run and replaced the method calls with the actual values. My guess would be to speed up the compilation time as it is done in runtime.

These are all my tries in .NET and as you can see I failed to achieve my goal. One could say that this is not possible but I want to look at a little C++ trick which can achieve just what I want. This trick is taken from a programming paradigm known as Generic Programming. This is the C++ code:

#include <iostream>

template <int N>
struct Fibonacci
{
  static const long result = Fibonacci<N-1>::result+Fibonacci<N-2>::result;
};

template <>
struct Fibonacci<0>
{
  static const long result = 0;
};

template <>
struct Fibonacci<1>
{
  static const long result = 1;
};


int main()
{
  std::cout << Fibonacci<45>::result;
  return 0;  
}

and when run, it compiles into this:

01001000  mov         ecx,dword ptr [__imp_std::cout (1002048h)] 
01001006  push        43A53F82h  ; 1134903170 decimal == 43A53F82 hexadecimal
0100100B  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (1002044h)]  

This is exactly what I wanted. The compiler simply pushes the 45th Fibonacci element onto the stack and calls cout. (In C++ arguments are passed using stdcall convention where all the arguments are pushed to the stack.)

That's it for this week.
Thank you for reading.

Boris.

Saturday, July 2, 2011

A text based, unparsed, context sensitive Xml viewer

Hi All,


Most modern programs today (in .NET) use Xml at some point of the other. If you have a configuration file it is written in Xml format. If you use human readable persistence or data transferal you probably do it using Xml. Many times you want to review a received XML with no real need to edit it. This was exactly the problem I was facing. 
In my application a user may receive some Xml data which he cannot edit but wants to view in a nice way. The user may interact with the Xml in a context sensitive manner meaning, if the user selected an Element he may get a different UI than when he selects an attribute. Previously I used a WebBrowser control which shows the Xml in a nice form (with folding) but it was not too customizeable (and to tell the truth I wanted to avoid COM and do something which is WPF based). The obvious solution was to use a tree. The Xml is organized in a tree based form anyway so a tweaked TreeView can be exactly what I needed. I looked around the internet and found this example: http://www.codeproject.com/KB/WPF/XMLViewer.aspx
The code in this example worked really well and I tweaked it a little to get the context sensitive nature I needed but there was one major drawback. It was not text editor based which made selections and other related interaction a hell. 
At this point I decided to write a simple text based viewer for my Xml. Before I continue I want to note that since I don't want to support editing I don't actually need a parser for my Xml. If full editing was needed then a parser would create the context sensitive functionality I need.


The editor I will be using is AvalonEdit which comes as a stand alone component in the SharpDevelop IDE. Whats nice about AvalonEdit is that I can get all the folding and coloring customization directly from the editor by setting SyntaxHighlighting="XML". For loading the Xml I am using XmlDocument (you can use XDocument if you like it better). I build a tree structure which represents the Xml where each node represents a single Xml element and the text range it takes within the text editor.


The base class for the ranges is:

 public abstract class BaseXmlTextRange : IComparable<BaseXmlTextRange>, IXPathProvider
  {
 
    protected const string IndentationString = "\t";
    /// <summary>
    /// The underlying node of the current range
    /// </summary>
    public XmlNode Node
    {
      get;
      protected set;
    }
 
    /// <summary>
    /// The start position of the current range
    /// </summary>
    public int Start
    {
      get;
      protected set;
    }
 
    /// <summary>
    /// The end position of the current range
    /// </summary>
    public int Length
    {
      get;
      protected set;
    }
 
    /// <summary>
    /// The last index of the range
    /// </summary>
    public int End
    {
      get
      {
        return Start + Length - 1;
      }
    }
 
    /// <summary>
    /// Represents the range that contains this range
    /// </summary>
    public BaseXmlTextRange Parent
    {
      get;
      set;
    }
 
    protected SortedSet<BaseXmlTextRange> _innerRanges;
 
    public BaseXmlTextRange(XmlNode node, int start)
    {
      _innerRanges = new SortedSet<BaseXmlTextRange>();
      Start = start;
      Node = node;
      Parent = null;
    }
 
    public ReadOnlyCollection<BaseXmlTextRange> InnerRanges
    {
      get
      {
        return new ReadOnlyCollection<BaseXmlTextRange>(_innerRanges.ToList());
      }
    }
 
    #region IComparable<BaseXmlTextRange> Members
 
    public int CompareTo(BaseXmlTextRange other)
    {
      if (other.Start > this.End) //other after this
        return this.End - other.Start;
 
      if (other.End < this.Start) //other before this
        return this.Start - other.End;
 
      throw new ArgumentException(String.Format("Ranges cannot overlap {0}-{1} and {2}-{3}", Start, End, other.Start, other.End));
    }
 
    #endregion
 
    public bool OffsetInRange(int offset)
    {
      if (offset >= Start && offset <= End)
        return true;
      return false;
    }
 
 
    #region IXPathProvider Members
 
    public IXPathProvider GetParent()
    {
      return Parent;
    }
 
 
    public abstract XPathData AppendXPathData(XPathData xPathData);
    #endregion
 
    public BaseXmlTextRange GetInnerRange(XmlNode xmlNode)
    {
      foreach (BaseXmlTextRange range in _innerRanges)
      {
        if (range.Node == xmlNode)
          return range;
      }
 
      return null;
    }
 
    /// <summary>
    /// Returns the smallest range corresponding to the given offset or null if the offset does not correspond to any range
    /// </summary>
    /// <param name="offset">The offset to look for</param>
    /// <returns></returns>
    public BaseXmlTextRange GetRangeByOffset(int offset)
    {
      if (!OffsetInRange(offset))
        return null;
 
      foreach (BaseXmlTextRange innerRange in _innerRanges)
      {
        if (innerRange.OffsetInRange(offset))
          return innerRange.GetRangeByOffset(offset);
      }
 
      return this;
    }
 
 
  }
I will give a brief explanation on most elements and you can fill in the details by examining the code. Each range holds the XmlNode which it represents. This can be either an Element, an Attribute, or a Value (the specific implementations are exactly for these node types). Each range holds the list of its inner ranges to create a tree like structure. The text editor "talks" with the ranges by providing an offset within the text therefore I provide a simple API method to locate a given node by the offset. Since Xml is a tree, I have the root node to start searching from.

Building the ranges is simple and is done through the following method:
    /// <summary>
    /// Builds the subtree of this range and returns the string that represents the associated node XML
    /// </summary>
    /// <param name="indentationLevel">The indentation level of this element</param>
    /// <returns></returns>
    public string BuildSubtree(int indentationLevel)
    {
      StringBuilder result = new StringBuilder();
 
      int count = 0; //Tracks the number of chars in this range
      result.Append(StringUtils.Repeat(IndentationString, indentationLevel));
      count += (indentationLevel * IndentationString.Length);
 
      result.Append("<");
      count++;
 
      result.Append(Node.Name);
      count += Node.Name.Length;
 
      result.Append(" ");
      count++;
 
      foreach (XmlAttribute attributeNode in Node.Attributes)
      {
        AttributeXmlTextRange attributeRange = new AttributeXmlTextRange(attributeNode, Start + count) { Parent = this };
        result.Append(attributeRange.BuildString());
        count += attributeRange.Length;
        _innerRanges.Add(attributeRange);
      }
 
      if (Node.ChildNodes.Count == 0) //No subelements!
      {
        result.Append("/>");
        count += 2;
 
        result.Append(Environment.NewLine);
        count += Environment.NewLine.Length;
      }
      else
      {
        //Close the element;
        result.Append(">");
        count++;
 
        result.Append(Environment.NewLine);
        count += Environment.NewLine.Length;
 
        foreach (XmlNode innerNode in Node.ChildNodes)
        {
          if (innerNode.NodeType == XmlNodeType.Element)
          {
            ElementXmlTextRange tempRange = new ElementXmlTextRange(innerNode, Start + count) { Parent = this };
            string innerElementString = tempRange.BuildSubtree(indentationLevel + 1);
            result.Append(innerElementString);
            _innerRanges.Add(tempRange);
            count += tempRange.Length;
          }
          else
            if (innerNode.NodeType == XmlNodeType.Text)
            {
              ValueXmlTextRange tempRange = new ValueXmlTextRange(innerNode, Start + count) { Parent = this };
              string innerElementString = tempRange.BuildString(indentationLevel + 1);
              result.Append(innerElementString);
              _innerRanges.Add(tempRange);
              count += tempRange.Length;
            }
        }
        //Append end element tag
        result.Append(StringUtils.Repeat(IndentationString, indentationLevel));
        count += indentationLevel;
 
        result.Append("</");
        count += 2;
 
        result.Append(Node.Name);
        count += Node.Name.Length;
 
        result.Append(">");
        count++;
 
        result.Append(Environment.NewLine);
        count += Environment.NewLine.Length;
      }
      Length = count;
      return result.ToString();
    }
I think the code speaks for itself but basically this is a recursive construction of Elements, Attributes, and Values using the ranges. The indentation level allows nice formatting of the text within the text editor. You can see the result in the following image:
An example application that uses the XmlTextViewer control

If you are interested in the code you can get it from my skydrive here.
Please note that while my code is under the CPOL license, AvalonEdit is under LGPL license.

Thank you for reading,
Boris