Solved

# TreeView Collections

Posted on 2006-06-01
Medium Priority
517 Views
This is less a question about treelists and more about collections.
Here goes:-

Dim tn as TreeNode
With TreeView1
tn = .Nodes.Add("Node 2")
tn.Nodes.Add("Node 2 - SubNode 1")
End With

If I was writing a treelist, how would I know that Node 2 - SubNode 1 is a node under Node 2?
The Add Function in Class Nodes is the same one.

or am I missing something?
0
• 6
• 6
• 4

LVL 4

Expert Comment

ID: 16807790
Hopefully this gets at what you are asking:

This demonstrates the beauty of object-oriented programming.  The calls to the Add method to add "Node 2" and "Node 2 - SubNode 1" are operating on two different instances of the TreeNode class.

Think of it this way.  The TreeView control has a collection of TreeNodes accessible through it's Nodes property.  Each TreeNode also has a collection of TreeNodes, accessible through a property that conveniently has same name: Nodes.  So
tn = .Nodes.Add("Node 2")
creates a new TreeNode and puts it in the TreeView's collection of TreeNodes (and also sets the variable tn to refer to it).  Now tn.Nodes refers to the collection of TreeNodes that belong to the TreeNode tn.  So
tn.Nodes.Add("Node 2 - SubNode 1")
creates a new TreeNode and puts it in tn's collection of TreeNodes.

Now if you were traversing the tree or had assigned a variable to the subnode like
tnsub = tn.Nodes.Add("Node 2 - SubNode 1")
to find out which TreeNode it belongs to, you would use the Parent property like
tnparent = tnsub.Parent
which in this case would return a reference to the exact same TreeNode as tn.
If you were to look at tn.Parent, you would find that it is Nothing, since it is a top-level node.

Hope this helps,
--Lance--
0

LVL 4

Expert Comment

ID: 16807888
Actually, small correction to my previous post.  The calls to the Add method in the example are NOT operating on two different instances of the TreeNode class.  The former is operating on the collection of TreeNodes in an instance of the TreeView class, and the latter is operating on the collection of TreeNodes in an instance of a TreeNode class.

However, if you then created another node tnsubsub = tnsub.Nodes.Add("Node 2 - SubNode 1 - SubSubNode 1"), then this Add would be operating on the collection of TreeNodes in the instance of the TreeNode class known as "Node 2 - SubNode 1".

Wow, I hope I made some sense in my ramblings...

--Lance--
0

LVL 4

Author Comment

ID: 16808098
Thanks, but how and when do you create the new instance, because if you step through the code, you still end up in

Public Function Add(byval Text as String) as TreeNode
Dim tr as new TreeNode
With tr
End With
...
Return(Me)
End Function

I find it easier to work through some code. Is that possible
0

LVL 86

Expert Comment

ID: 16808171
If you want to add a Node to an already existing Node then you need a reference to that existing Node...

Or you could pass in a "full path" description of the node you want to add:

Then you could make a recursive algorithm that descends down the tree structure creating nodes as necessary to fill in the missing pieces.
0

LVL 4

Expert Comment

ID: 16808553
Just curious, where did you get that bit of code (which looks like it would be code within the .NET Framework itself).  I have generally been working with the .NET Framework as a bit of a "black box", so if I step through code, it goes right on to the next line of code after the .Add method call.

But if the piece of code you provided is indeed what is really being run when .Add is called, I can see where your confusion comes from.  I would expect the last line to be Return(tr), not Return(Me).  The Me refers to the instance of the TreeNodeCollection returned by the .Nodes method, so returning the entire collection (itself), and not the newly created TreeNode (tr) makes no sense at all.

In the debugger, could you check to see what the type and value of Me are?

--Lance--
0

LVL 4

Author Comment

ID: 16808672
Sorry if I confused you. I am actually writing my own treeview, and I wanted it ton have the same methods, properties etc as the microsoft one.

What I have done so far is to have a usercontrol which draws the image,text +- lines etc, and I use a control for each line in the treeview. I need to know if there are children and parents in order to draw the lines, +- etc properly.

The way the standard treeview works suggests that the Add function ends with a Return statement because you can code
tn = Treeview1.Nodes.Add("Node 2")

I am trying to work out when to offset the text etc. as well as which nodes to collapse, but I want to do it using the same structure as the treeview and not use additional arguments.

But all I am managing to do is to confuse myself..
0

LVL 86

Expert Comment

ID: 16808773
Writing a TreeView is not a trivial task...  =)

What different behaviour do you want?

Would it be possible to Inherit from the TreeView instead of writing one from scratch?

How are you storing/representing the nodes in your TreeView implementation?

0

LVL 4

Author Comment

ID: 16808843
Firstly, I write code entirely on my own and this forum is a great way of talking to others. Simply asking the question helps.

I am writing a treeview because I want it to be transparent.

I have already written a transparent listview, but that doesn't mimic the windows listview.

I don't intend to publish these controls, so I don't really need to mimic the standard interface, but I thought I might learn something.

Inheriting the control does not allow me to make it transparent.
0

LVL 86

Expert Comment

ID: 16808895
"I need to know if there are children and parents in order to draw the lines, +- etc properly."

How are you storing/representing the nodes in your TreeView implementation?
0

LVL 4

Author Comment

ID: 16808925
As I have indicated, I draw +- boxes, lines etc on the usercontrol.
I have properties that govern how and which lines are drawn.
eg HasChild as Boolean if true, draws a box with + in it
IsCollapsed draws - or + etc
0

LVL 86

Expert Comment

ID: 16809239
I understand that part silly...  =)

I'm tyring to figure out exactly ~where~ you need help.

It seems like you are trying to understand INTERNALLY (inside the class, not externally with respect to how they are drawn) how the nodes are related to and reference each other so that you can determine what needs to be drawn externally.

Thus my question about how you are STORING the nodes.  Are they being kept in an ArrayList for example?  Are you using the standard TreeNode class or have you written your own representation of that as well?

etc...

cavehop was describing how they are represented in the TreeView:

"The TreeView control has a collection of TreeNodes accessible through it's Nodes property.  Each TreeNode also has a collection of TreeNodes..."

So you need to keep "Lists of Lists".  You essentially nest each sub TreeView structure inside its parent TreeNode.  Those nodes at the root level are stored by the Nodes collection of the TreeView itself.

0

LVL 4

Accepted Solution

cavehop earned 1000 total points
ID: 16809580
Agreed, definitely not a trivial task.

Idle Mind is right on that the way you store/represent a node (and a collection of nodes) is critical to knowing how to answer that question.

Assuming you have a TreeNode class and one of its data members is a collection of some sort that stores the children TreeNodes, if you are mimicing the standard interface, you will need a class to represent the collection of TreeNodes (namely a TreeNodeCollection) that implements the IList, ICollection, and IEnumerable interfaces.  The Add method you listed above should be a method of the TreeNodeCollection.

To answer the question "how and when do you create the new instance", it is indeed in the Add method (namely the Dim tr as new TreeNode statement).  However, the Add method needs to return that newly created TreeNode, so the last line should be Return(tr).

Now, if I understand correctly, one of the things you are looking for is essentially "What code would go in the Parent property of a TreeNode class that would correctly return the parent node?"  It seems to me the easiest way to do this would be to have a data member of type TreeNode that keeps track of the parent TreeNode in both the TreeNode class and the TreeNodeCollection class.  When a TreeNode gets created, the first thing it does is create a new TreeNodeCollection (initally empty) for its children and it sets the TreeNodeCollection's parent to itself.  Then whenever the TreeNodeCollection's Add method is called, it sets the parent of the newly created TreeNode to it's own parent TreeNode.  Then a TreeNode's Parent property would simply return the value of its parent data member.

The last thing is that the TreeView class would a data member of type TreeNodeCollection (that would get returned by the Nodes method).

Something along the lines of (and I'm just typing this straight out, so there may be typos and it will be missing any auto-generated code, inherited classes, etc.):

Public Class TreeView
Private _childNodes As New TreeNodeCollection

Public ReadOnly Property Nodes() As TreeNodeCollection
Get
Return _childNodes
End Get
End Property
End Class

Public Class TreeNode
Private _childNodes As TreeNodeCollection
Private _parentNode As TreeNode = Nothing

Private Sub New()
_childNodes = New TreeNodeCollection(Me) ' Set collection's parent to me
End Sub

Private Sub New(tr As TreeNode)
_childNodes = New TreeNodeCollection(Me)
_parentNode = tr
End Sub

Public ReadOnly Property Nodes() As TreeNodeCollection
Get
Return _childNodes
End Get
End Property
End Class

Public Class TreeNodeCollection
Implements IList, ICollection, IEnumerable

Private _nodeCol As New Collection ' or whatever collection class suits you best
Private _parentNode as TreeNode = Nothing

Private Sub New()
' Collection has no parent (i.e. it is probably a collection owned by a TreeView)
End Sub

Private Sub New(tr As TreeNode)
_parentNode = tr ' Collection owned by tr
End Sub

Public Function Add() As TreeNode
Dim tr As New TreeNode(_parentNode) ' Set parent of new node to collection's parent
_nodeCol.Add(tr) ' Or whatever is appropriate for your collection class
Return tr ' Return the newly created TreeNode
End Function

Public ReadOnly Property Parent() As TreeNode
Get
Return _parentNode
End Get
End Property
End Class
0

LVL 4

Expert Comment

ID: 16809623
The last thing is that the TreeView class would ~have~ a data member of type TreeNodeCollection (that would get returned by the Nodes method).
0

LVL 4

Author Comment

ID: 16816317
I need to get my head around this, and I know I've been here before in VB6.
I may need to post some more qs on this.

Neither of you came back to say, "transparent treeview? no problem - here's the code"

I take it that there is none.
0

LVL 4

Expert Comment

ID: 16817315
Transparent TreeView ... well that got me to thinking (and therefore Googling).  I could not find anyone who had "re-written" the TreeView (mostly I found enhancements to the existing TreeView), but I did find this interesting site that you might be interested in as well:
http://www.aisto.com/roeder/dotnet/
In particular, the application Reflector for .NET lets you look at the code behind the .NET assemblies (in the language of your choice, no less).  Very cool.
0

LVL 4

Author Comment

ID: 16822832
You may be interested in this. (I don't know)

One of the problems of EE is I often ask the wrong question.
Because I used the ideas cavehop put forward, and I had problems with events. This reminded me of my long ago previous problem with collections which had to do with different views in an external application.

So I sat down and re-thought the problem, and it turned out (although the code is not fully written) that there is a much simpler answer.

I have a collection of user controls, which replicate the nodes of a treeview, which in turn sit inside my own treeview control. In this control, I have a function
Public Function Node(Byval Key as String) as TreeItem (this is my node)
- and here I rememebred that I could also have another function
Public Function Node(Byval ParentKey as String, Key as String)
and it all started to fall into place.
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A while ago, I was working on a Windows Forms application and I needed a special label control with reflection (glass) effect to show some titles in a stylish way. I've always enjoyed working with graphics, but it's never too clever to re-invent â€¦
Itâ€™s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following â€¦
Are you ready to place your question in front of subject-matter experts for more timely responses? With the release of Priority Question, Premium Members, Team Accounts and Qualified Experts can now identify the emergent level of their issue, signalâ€¦
Loops Section Overview
###### Suggested Courses
Course of the Month15 days, 17 hours left to enroll

#### 850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.