Introduction

A vast majority of successful applications use the tree control to display a variety of information to the user. The tree control has become so ubiquitous that the users are very familiar with its operations. One of the common problems with the tree control is saving the state between sessions. This article presents a class
TBTreeStateMgr that makes it effortless to save and restore the state of multiple trees.

What is a tree state ?

The tree state consists of

The expanded state, which nodes are expanded and which are collapsed

The selection state, which nodes are selected

The visibility state, which nodes are currently visible

Currently, the TBTreeStateMgr only stores the expanded state.

Highlights

The following are the highlights of TBTreeStateMgr implementation:

Can handle multiple tree instances

Each tree instance must be assigned a unique tree ID

Uses XML to store/load the tree states

All methods in TBTreeStateMgr are declared static. This is due to the fact that a single instance of
TBTreeStateMgr can handle storage of a number of tree states.

TBTreeStateMgr is threadsafe

Uses COM Structured Storage to store individual XML files

Using TBTreeStateMgr

Include the following header file in your project

#include"TBTreeStateMgr.h"

Ensure that CoInitialize or OleInitialize is called in the
InitInstance function

Note: This function is typically called just after initializing the tree control with the data For example: in the OnInitialUpdate() function

//This call restores the wnd_TreeCtrl to a state stored under the name <code>"My Tree1 View"
TBTreeStateMgr::LoadTreeState(_T("My Tree1 View"),&wnd_TreeCtrl);

[OPTIONAL] Change the storage file.

The TBTreeStateMgr by default stores the Structured Storage file in the current directory under the file name "CTLStateStg.ctss", if you want to specify a different directory or path use the
SetStorageFile(LPCTSTR lpszNewFile)

To reset all tree states, simply delete the "CtlStateStg.ctss" file. This file will be automatically generated if it is not found

Implementation

This section describes in short some of the implementation choices I had to make. I hope my use of XML and
IStorage/IStream in this project will demonstrate how powerful these tools are. Structured Storage is in fact used by MSWord. The DOC format is actually a
IStorage compatible file.

Conventional approaches

There are many mechanisms to store and retrieve tree states. A popular approach seems to be to store the tree state in the registry. For document/view applications that use the tree control, some developers choose to store the latest tree state as part of the document. So each document will be able to restore its view to the state when it was last closed.
The registry method is not secure, safe nor scalable. Most projects do not have the luxury of modifying the document file to
accommodate storing the latest state. In any case, it is a bad idea to store the view state along with the document object.

Enter XML

While I was evaluating techniques to store the tree control state, I stumbled upon XML. XML is also highly tree structured. If we could somehow transfer the tree state to an XML document efficiently and back, we could have a really cool solution. The MSXML parser is highly efficient and widely available with IE5 deployments. The bulk of the code in
TBTreeStateMgr is devoted to translating the tree state to XML and back. The XML DTD for this project is:

IStorage/IStream

The next major problem was : How to store multiple trees ?

If you open the CtlState.ctss using the "Docfile Viewer" we can see the following structure:

As the above figure shows, the DOCfile stores each XML document in a separate stream.
The reason for this architecture is: Any large scale application would have to deal with multiple trees (or) with multiple users view of the same tree. An application may also have trees in the views of multiple documents. For example: Each book document can have a tree view showing the table of
contents. If we created a different XML Document for each tree instance, we may end up with hundreds of files. Another reassuring factor was Structured Storage is used extensively by MS in its own products (MSWord/Excel store DOC,XLS files in Structured Storage)

Enhancements

This can be enhanced to support storage of any state. Just change the XML DTD to add elements of your own liking. For example: this can be enhanced to save/restore state of
Toolbars, Windows, Splitter Windows, List, Grid.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

i try to run the demo project, but it ended up to be 131 erros, mostly cant detect the declaration for the xml format. Example: error C2143: syntax error : missing ';' before '*' in the (static IXMLDOMDocument * pDoc; // XML Document).

I already install the msxml version 4, and also try to copy the msxml.dll into the same directory, but the same errors occured. Please help.

Mr. Vivek,
Your article looks great, but the source simply does not
compile on my machine; the IStream, IStorage and other interfaces are alien to my compiler.
One more Que. where can I get the Docfile viewer?

Hi Vivek, This looks like a good, clean and straightforward method to persist Tree control data. Thanks for sharing it with us.

My only question is whether you have done any performance tests on large trees, say around +100K items. When I had a brief play with MSXML about 18 months ago it was useless for XML files this size. ie. It took forever to load the file, sometimes crashed, and when it did work it would use a ridiculous amount of memory. MS may well have addressed these issues by now but I haven't tried this since, so I don't know. The problem I saw may also not apply to your code.

And finally you may well say this is irrelevant as you never intended it to be used for large collections, and that's fine.

Thanks! There should be no problem storing large tree structures. The XML file contains only the nodes that have been expanded. I think it is reasonable to assume that even if a tree has 100K+ items, only a fraction of the nodes will be expanded. Also Microsoft has improved the MSXML parser a great deal recently.

The main problem is the MFC Tree control is notoriously slow in DeleteAllItems. I tried the demo with 200K nodes on the far right hand tree (see the GUI picture in the article). I found that the XML storing/retreiving itself took 20ms. For 100K, the XML storage took 10ms. However, destroying the tree control took 8.1 secs for 100K nodes and 22s for 220K nodes.

In my project, I use this tree state manager on trees which have 80K nodes. NO problem, because we use a look ahead loading mechanism, only load the expanded nodes and its children.

I uploaded a new demo with 50K nodes, you can see that there is no overhead due to the XML storing.

Vivek,
When I was working on the ClassView Tree in my programmer's editor, ED4W I had major problems with the MS Tree Ctrl. Populating the tree for the all of the classes/functions etc. in MFC/VC CRT could take over 30 minutes, which made it completely unusable. The Tree also gets updated in real time in a background thread and this was also taking too long to delete and insert items. This was with 100K+ items in the tree.

In the end I wrote my own tree control which doesn't maintain any data in it's own right, and is simply a view into the real data which in this case is in a database I've written. This approach works extremelly well and it's speed is that of the underlying data source. For another post on this see A better way.