Remove a Node from TreeView?

N

Nicky Smith

Hello,

I've got a problem with a TreeView. I get a starnge error when trying
to call the .Remove method.

The method is called from a ContextMenu, when holding the stylus down
on a childnode.

I then call the Remove method like this:

If MessageBox.Show("Are you sure?", "Delete Item?",
MessageBoxButtons.YesNoCancel, _
MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
= DialogResult.Yes Then
Dim TN As TreeNode = TV1.SelectedNode

TV1.Nodes.Remove(TN)

End If

This throws an Arguement Out of Range exception, on the call to
Remove(). I don't undeerstand that, because the TN object does become
a valid tree node, and the Remove method accepts a TreeNode as an
argument!

What am I doing wrong?
 
P

Peter Foot [MVP]

What is probably the cause is that when you fire the messagebox the treeview
loses focus and so the item is no longer selected. Store the selected item
before you show the messagebox, then pass the reference into Remove.

Peter

--
Peter Foot
Windows Embedded MVP
www.inthehand.com | www.opennetcf.org

Do have an opinion on the effectiveness of Microsoft Windows Mobile and
Embedded newsgroups? Let us know!
https://www.windowsembeddedeval.com/community/newsgroups
 
N

Nicky Smith

Hi,

I tried adjusting the code like this:

Dim TN As TreeNode

Try
'this sub delete nodes, but does not allow a user to
delete a root node
If TV1.SelectedNode.Parent Is Nothing Then
MessageBox.Show("You may NOT delete a main item!")
Exit Sub

Else
TN = TV1.SelectedNode
End If

If MessageBox.Show("Are you sure?", "Delete Item?",
MessageBoxButtons.YesNoCancel, _
MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
= DialogResult.Yes Then

'MessageBox.Show(TN.Parent.ToString)
TV1.Nodes.Remove(TN)

End If
Catch ex As Exception
MessageBox.Show("Error: " & ex.Message & " in
mnuRemoveItem_Click", "Error")

End Try

You can see the message box just before the call to .Remove that I
used for debuging, this works, and reports the parent node of the
selected node. So I'm stuck! This is starting to look like a bug ...

-N
 
N

Nicky Smith

Hello again,

The problem I'm describing, seems only to affect child nodes.
Root nodes are deleted without any problems.

I just made a little uncomlicated app that tests this behaviour:


'ADD A CHILD NODE to the Root Node added in form load()

Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnAdd.Click
Try

TV1.Nodes(0).Nodes.Add(InputBox("Node text", "Node Text",
"sample text"))

Catch ex As Exception
MsgBox("Error in Add")
End Try
End Sub


'DELETE A NODE -----------------------------------------
Private Sub btnDelNode_Click(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles btnDelNode.Click
Try
Dim TN As TreeNode = TV1.SelectedNode
TV1.Nodes.Remove(TN)

Catch ex As Exception
MsgBox("Error in DelNode: " & ex.Message)
End Try
End Sub

'FORM LOAD ---------------------------------------------------
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
TV1.Nodes.Add("MyRootNode")

End Sub

'END---------------------------------

This also throws an Argument Out of Range exception. I don't know what
to do!

..Remove() can not be overloaded, so I can't look for help there. Does
anyone know of a workaround?

-nick
 
N

Nicky Smith

Hello,

I've found a workaround for this bug (and it is a bug!)

You can't call the remove method of the parent node, but you can call
the .Remove method of the reference node:

This raises the error:

Dim TN As TreeNode = TV1.SelectedNode
TV1.Nodes.Remove(TN)

This works as expected:

Dim TN As TreeNode = TV1.SelectedNode
TN.Remove()

I've tried this on the emulator without SP1 or 2 and on a device with
SP2 and the bug exists in both scenarios.

The .Remove method is documented in the .Net msdn help files using the
first version with a reference as an argument for the remove method.
(.remove(tn))

-N
 
A

Alex Feinman [MVP]

Why do you expect to be able to remove a non-root node by calling Remove on
the treeview itself?
When you add a node, you add it to TreeView.Nodes(0).Nodes
When you remove it, you should be removing it by calling
TreeView.Nodes(0).Nodes.Remove and not TreeView.Nodes.Remove.
You get OutOfRangeException because the node does not belong to a collection
from which you are trying to remove it.
Alternatively you can use
if TreeView.SelectedNode.ParentNode Is Nothing then
TreeView.Nodes.Remove(TreeView.SelectedNode)
else
TreeView.SelectedNode.ParentNode.Remove(TreeView.SelectedNode)
end if
 
N

Nicky Smith

Why do you expect to be able to remove a non-root node by calling Remove on
the treeview itself?

Well, consider this code:

TV1.Nodes.Remove(TV1.SelectedNode)

This is removing a Treenode from the Nodes collection of the entire
TreeView control. And no, it is not removing a root node. The app
isn't allowed to remove the root nodes.

And it works.

As long as it is on the desktop version of the .Net framework. It is
broken in the CF runtime. I came across this problem becausing I'm
porting a desktop prototype of the app to the CF.

The .Selected node property isn't just a simple Index number of a node
in a particular collection, it is a reference to a complete node.
Therefor, I would imagine that it isn't a big deal for the Treeview to
locate the selected node, no matter where in the collection. Root,
child or grandchild.

Also, Microsofts own documentation in the .Net SDK looks like this:

-snip
Case MouseButtons.Right
treeView1.GetNodeAt(e.X, e.Y).Remove()
-snip

This is right-clicking to remove a node, and as you can see, there is
no need to manover to child nodes. The GetNodeAt method simply gets a
reference to the node that was right clicked using the screen
coordinates of the mouse click, and then the remove method is called.
When you add a node, you add it to TreeView.Nodes(0).Nodes
When you remove it, you should be removing it by calling
TreeView.Nodes(0).Nodes.Remove and not TreeView.Nodes.Remove.

If that were the case, a Treeview with many nested nodes and child
nodes would start to look pretty ugly when using the method you
describe above, for example, a node that is just 5 deep:

TreeView1.Nodes(X).Nodes(Y).Nodes(Z).Nodes(A).Nodes(B).Remove

Yak!

No, there should be an easy way to get a reference to a node no matter
where it is.
You get OutOfRangeException because the node does not belong to a collection
from which you are trying to remove it.

Yes, but only in the CF version, and the difference here, bug or
intentional, isn't documented. Well, I haven't found it.
Alternatively you can use
if TreeView.SelectedNode.ParentNode Is Nothing then
TreeView.Nodes.Remove(TreeView.SelectedNode)
else
TreeView.SelectedNode.ParentNode.Remove(TreeView.SelectedNode)
end if

I use a quick check like that to prevent users from deleting the root
nodes.

But I think, this is a more elegant way to remove a node without
having to worry about which collection it is in:

Dim TN as TreeNode
TN = TreeView1.Nodes.SelectedNode
TN.Remove()

This works in both the full and the Compact frameworks.
 
N

Nicky Smith

Hello,

After working with the problem of removing a child node from an
unknown, depth and position in the treeview (or finding a method that
works in the CF just as it does in the full framework), I've also
found that this works just as well with both runtimes:

TreeView1.SelectedNode.Remove()

so as you can see, you don't even have to get a reference like I did
with the first solution:

Dim TN as TreeNode = TreeView1.SelectedNode()
TN.Remove

The .Selectednode property also allows a convienient way to add child
nodes to any node selected, at any depth:

Treeview1.SelectedNode.Nodes.Add("Child Node")

I've tested them with the 1.1 framework on the desktop, the 1.0 CF
(with no service packs) on the emulator, and on a device with CF 1.0
and SP2.

-N
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top