5,276,406 members and growing! (15,949 online)
Email Password   helpLost your password?
Desktop Development » Tree Controls » TreeView Controls     Intermediate

Hierarchical TreeView control with data binding enabled

By Mike Chaliy

The control extends standard TreeView control to make it fully data bind.
C#, Windows, .NET 1.1, .NET, WinForms, VS, VS.NET2003, Dev

Posted: 27 Mar 2005
Updated: 27 Mar 2005
Views: 75,344
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
11 votes for this Article.
Popularity: 4.01 Rating: 3.85 out of 5
1 vote, 9.1%
1
1 vote, 9.1%
2
0 votes, 0.0%
3
5 votes, 45.5%
4
4 votes, 36.4%
5

Sample Image - bindablehierarchicaltree.gif

Introduction

Some time ago, my task was to write something like a virtual file system. Of course, I decided to use typed DataSets because I have already written a framework to work and update them easily. With this technology, it is very easy to display the content of a folder. Relational DataTables are very great tools for this. That’s all right, but when I saw the result - I died! That was not the look and feel that I had mentioned to my client! So I opened Google and started searching for TreeView with data binding enabled. Of course, I found something: this (Data Binding TreeView in C#) was pretty but that was not the hierarchy in my mind; this (How to fill hierarchical data into a TreeView using base classes and data providers) was pretty too but I didn't understand why the author doesn't like standard binding. Both were not for me! And as a real Ukrainian man, I decided to write my own!

Binding implementation

First of all, we need a method to fill all the data in the tree view. For this, I store references of the data items in the ArrayList. This gives me an indicator of the items that are not in the tree. I will iterate through the items until the length of this array becomes 0. This realization will throw an exception if some of the items cannot find their places in the try. If you need another realization of this (for example do nothing or store these items on the bottom of the root node) please let me know. I will try to update this article.

ArrayList unsortedNodes = new ArrayList(); 
//This is list of items that still have no place in tree


for (int i = 0; i < this.listManager.Count; i++)
{
    //Fill this list with all items.

    unsortedNodes.Add(this.CreateNode(this.listManager, i));
}

int startCount;

//Iterate until list will not empty.

while (unsortedNodes.Count > 0)
{    
    startCount = unsortedNodes.Count;

    for (int i = unsortedNodes.Count-1; i >= 0 ; i--)
    {                    
        if (this.TryAddNode((DataTreeViewNode)unsortedNodes[i]))
        {
            //Item found its place.

            unsortedNodes.RemoveAt(i);
        }
    }

    if (startCount == unsortedNodes.Count)
    {
        //Throw if nothing was done, in another way this 

        //will continuous loop.

        throw new ApplicationException("Tree view confused 
                      when try to make your data hierarchical.");
    }
}

private bool TryAddNode(DataTreeViewNode node)
{
    if (this.IsIDNull(node.ParentID))
    {
        //If parent is null this mean that this is root node.

        this.AddNode(this.Nodes, node);                
        return true;
    }
    else
    {
        if (this.items_Identifiers.ContainsKey(node.ParentID))
        {
            //Parent already exists in tree so we can add item to it.

            TreeNode parentNode = 
                    this.items_Identifiers[node.ParentID] as TreeNode;
            if (parentNode != null)
            {
                this.AddNode(parentNode.Nodes, node);                
                return true;
            }
        }
    }
    //Parent was not found at this point.

    return false;
}

Respond to external data changes

Okay… Now we have our tree view filled with all items. Second one that we need is to respond to external data changes. For this we need to handle the ListChanged event of the current context.

((IBindingList)this.listManager.List).ListChanged += 
                     new ListChangedEventHandler(DataTreeView_ListChanged);

Realization of the handle is very simple.

private void DataTreeView_ListChanged(object sender, ListChangedEventArgs e)
{            
    switch(e.ListChangedType)
    {
        case ListChangedType.ItemAdded:
            //Add item here.

            break;

        case ListChangedType.ItemChanged:
            //Change node associated with this item

            break;

        case ListChangedType.ItemMoved:
            //Parent changed.

            break;

        case ListChangedType.ItemDeleted:
            //Item removed

            break;                    

        case ListChangedType.Reset:
            //This reset all data and control need to refill all data.

            break;
        
    }
}

Now our control particularly supports data binding. You are able to see data, it will change synchronously with external data.

Selected node

You can ask what additional functionality is required? -Oh! this only the start.

So next point: If you change the data source position our control will not change it. Currency manager has a PositionChanged event. We will use it.

this.listManager.PositionChanged += 
                  new EventHandler(listManager_PositionChanged);

At the start point, we added index for positions and nodes according to them. This gives us an easy way to find a node by its position. So this short code will give us the ability to find the selected node by its position.

DataTreeViewNode node = 
          this.items_Positions[this.listManager.Position] as DataTreeViewNode;
if (node != null)
{
    this.SelectedNode = node;
}

Current context position

Now you are not able to use this control as parent to your table. Basically all that we need is according to the selection of the node, change position of the context. This is not a problem as we store position of the item in each node. Make the AfterSelect event:

private void DataTreeView_AfterSelect(object sender,
                              System.Windows.Forms.TreeViewEventArgs e)
{    
    DataTreeViewNode node = e.Node as DataTreeViewNode;
    if (node != null)
    {
        //Set position.

        this.listManager.Position = node.Position;
    }
}

Label editing

Not a problem! Just use AfterLabelEdit.

private void DataTreeView_AfterLabelEdit(object sender, 
                           System.Windows.Forms.NodeLabelEditEventArgs e)
{
    DataTreeViewNode node = e.Node as DataTreeViewNode;
    if (node != null)
    {
        //This will found appropriate converter for 

        //type and see if it can convert from string. 

        if (this.PrepareValueConvertor()
          && this.valueConverter.IsValid(e.Label)//Lets converter to check value.

           )
        {
            //Set property.

            this.nameProperty.SetValue(
                this.listManager.List[node.Position],
                this.valueConverter.ConvertFromString(e.Label)
                );
            this.listManager.EndCurrentEdit();
            return;
        }
    }
    //Node text are not editable.

    e.CancelEdit = true;
}

Using the code

As DataSource you can use any data that, for example, DataGrid can use. You can use any type of columns to bind. Basically, only the name column is limited to types that can be converted from string. This applies only when EditLabel is true.

In most cases data must have three columns: Identifier, Name and Identifier of parent row. If you need something like 'FirstName + " " + LastName' as Name field - you can make autocomputed columns in DataSet.

I am not including image index in binding because I didn't need it. Let me know if you need this functionality. I will update this article.

Bonuses

First bonus is full design time support. Unlike all other data bound trees on “Code Project”, this tree view has all standard designers that, for example, DataGrid has (of course, with some changes, see Design namespace). Second one is roundup framework bug with bottom scrollbar in TreeView (scroll bar is visible all the time, even if it is not needed at all).

That’s all! Enjoy. Visit my blog for the latest news!

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.

A list of licenses authors might use can be found here

About the Author

Mike Chaliy


Ukrainian Developer Community
Occupation: Web Developer
Location: Ukraine Ukraine

Other popular Tree Controls articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 26 (Total in Forum: 26) (Refresh)FirstPrevNext
Subject  Author Date 
GeneralVB.NET CodememberHow Many Times5:58 31 May '08  
QuestionAbout Gridview control in asp.net 2.0 + Data bindingmemberSamiullah21:46 27 May '08  
QuestionRecursivememberdanielab8:01 6 Sep '07  
QuestionTreeView COnfused when using filtered BindingSOurcemembercorsairX23:21 9 Nov '06  
QuestionDo we have the right version?memberthrowit120:43 9 Aug '06  
GeneralAbout hide the HScrollbar in TreeViewmemberbjleo0:33 14 Feb '06  
GeneralRe: About hide the HScrollbar in TreeViewmemberMike Chaliy0:45 14 Feb '06  
QuestionChanging Parent BugmemberEmma M0:21 18 Jan '06  
QuestionImplementing Drag and DropmemberEmma M7:13 16 Jan '06  
AnswerRe: Implementing Drag and DropmemberMike Chaliy11:11 16 Jan '06  
GeneralRe: Implementing Drag and DropmemberEmma M23:34 16 Jan '06  
AnswerRe: Implementing Drag and DropmemberJeremy Thomas17:02 13 Feb '06  
GeneralRe: Implementing Drag and DropmemberEmma M23:10 13 Feb '06  
GeneralRe: Implementing Drag and DropmemberSmithSystems17:39 24 Feb '06  
GeneralRe: Implementing Drag and DropmemberNickOberoi12:08 13 Feb '08  
Generalbug not only when deletememberbyx4510:10 23 Oct '05  
GeneralRe: bug not only when deletememberMike Chaliy4:08 11 Nov '05  
GeneralProblems using custom collectionmemberhcan11:32 21 Jul '05  
GeneralRe: Problems using custom collectionmemberMike Chaliy4:07 11 Nov '05  
GeneralThis version of the control are fault.memberMike Chaliy1:18 27 May '05  
GeneralSmall Bugmembertelcoex12:05 18 May '05  
GeneralThe whole 9 yards - getting it all to workmemberFoxman997:05 5 May '05  
GeneralRe: The whole 9 yards - getting it all to workmemberMike Chaliy17:00 5 May '05  
GeneralForm DesignmemberPeter Bourget11:31 8 Apr '05  
GeneralRe: Form DesignmemberMike Chaliy7:25 12 Apr '05  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 27 Mar 2005
Editor: Sumalatha K.R.
Copyright 2005 by Mike Chaliy
Everything else Copyright © CodeProject, 1999-2008
Web12 | Advertise on the Code Project