views:

340

answers:

3

First off we have the almighty code!

List nodes = new List();
TreeNode Temp = new TreeNode();

TreeNodeCollection nodeList = treeViewTab4DirectoryTree.Nodes;

while (nodeList.Count != 0)
{
    Temp = nodeList[0];

    while (Temp.FirstNode != null)
    {
        Temp = Temp.FirstNode;
    }

    if (!nodes.Contains(Temp.FullPath))
    {
        nodes.Add(Temp.Text);
    }

    nodeList.Remove(Temp);
}

Now the problem: I have written the code above with the intent of creating a List containing the text from all the nodes in the tree. That works perfectly. The problem I am having is when I remove the nodes from my variable they are also being removed from the actual list. The question would be how can I make a copy of the list of nodes so I can play with them without messing with the ACTUAL list. How do I make a copy of it without just making a reference to it? Any help will be greatly appreciated!

+2  A: 

Your problem arises because "nodeList" is a reference to treeViewTab4DirectoryTree.Nodes, rather than a copy of it.

The solution depends entirely on the what type of TreeNodeCollection you're using (WinForms, ASP.net, something else?), as you'll need to look for a .Copy(), .Clone(), .ToArray() method or similar to take a copy of the contents of the collection, rather than a reference to the existing collection.

If, for example, you're using asp.net and thus the System.Web.UI.WebControls.TreeNodeCollection, you could use the .CopyTo method in a way similar to this:

TreeNode[] x = null;
treeViewTab4DirectoryTree.Nodes.CopyTo(x, 0);
Rob
@Rob I tried your code but the compiler told be that the destination array can't be null, and it also can't be unassigned. Is there any way to make it dynamic? Would a list work if the signature for CopyTo specifically calls for an Array?
Adkins
@Adkins, You'll probably have to initialise the array prior to using it then, the specifics of that will be down to the TreeNode type you're using. Essentially the thrust of my answer is that you need to make a *new* collection to remove items from, rather than removing them from nodeList or treeViewTab4DirectoryTree.Nodes.Instead, could you have a List<TreeNode> that you **add** the nodes that you want to keep to (or the ones you want to remove), rather than attempting to modify an existing collection?
Rob
I can't implicitly convert between the types TreeNodeCollection and a collection of TreeNode elements (? huh ?). I can however foreach through the TreeNodeCollection adding each one to the collection of TreeNode's. Thanks for the pointers!
Adkins
@Rob worked perfectly! Thanks for the help.
Adkins
+2  A: 
Arne Sostack
@Arne I tried to create a list as you said, but received an error that the constructor was getting an improper parameter. I checked it over and it is getting exactly what it wants, but I can't get rid of the error message.
Adkins
@Arne also the loop that you suggested only returns the first child of each of the root nodes. That was why I was removing elements. When I was completely looped through one of them I removed it. When there were no more to remove then I was finished.
Adkins
@Arne Standard WinForms TreeNodeCollection is not IEnumerable : for discussion on making it IEnumerable compatible and sample code for iterating using Linq check out : http://stackoverflow.com/questions/1815497/enumerating-collections-that-are-not-inherently-ienumerable
BillW
@Adkins - Ah yes, I missed a detail - you're actually removing every node in the tree from the collection of root nodes, that's what threw me off.I think I'd prefer a stack based solution then (or recursion), mostly because the next guy to read the code will have an easier time figuring out what it does.Will edit to show it done with a stack.
Arne Sostack
@BillW - Actually, it *is* IEnumerable, just not IEnumerable<TreeNode>
Arne Sostack
@Arne +1 Stack based update is great; if based on "mrydengren's" answer in the SO link I referred you to, please do give him some credit, and might be good to add a link to the Wes Dyer article mentioned there as cited by Eric Lippert. You are right : standard WinForms TreeView Nodes collection is IEnumerable, and IEnumerable<TreeNode> is not : which means I need to go back and see why I had such trouble using Linq with the TreeNodes collection in the first place. Thanks !
BillW
@BillW - Thanks ;) I didn't actually get around to checking the link. The stack based approach was something I had just recently thought up after a discussion about recursion and how it was useful to know but mostly in order to know how to avoid it.
Arne Sostack
A: 

@Arne

I have the same problem. Although almost the same...

I have a treeview with nodes. I want to keep a copy of the original nodes before editing. After I made a copy i delete a subnode, but it is also deleted in my array. Strange?

Any idea??

Code:

    public Form1()
    {
        InitializeComponent();
    }

    private TreeNode[] _storeArray;
    private List<TreeNode> _storeList;

    private void Form1_Load(object sender, EventArgs e)
    {
        FillTreeview();

        Console.WriteLine("In store: " + _storeArray[1].Nodes.Count);
        Console.WriteLine("In original: " + _storeList[1].Nodes.Count);
    }

    private void FillTreeview()
    {
        TreeNode newNode = new TreeNode();
        newNode.Text = "RootNode 1";
        newNode.Nodes.Add("SubNode 1");
        newNode.Nodes.Add("SubNode 2");
        newNode.Nodes.Add("SubNode 3");
        newNode.Nodes.Add("SubNode 4");

        treeView1.Nodes.Add(newNode);

        TreeNode newNode2 = new TreeNode("RootNode 2");
        newNode2.Nodes.Add("SubNode 1");
        newNode2.Nodes.Add("SubNode 2");
        newNode2.Nodes.Add("SubNode 3");

        treeView1.Nodes.Add(newNode2);

        _storeArray = new TreeNode[treeView1.Nodes.Count];
        treeView1.Nodes.CopyTo(_storeArray, 0);

        _storeList = new List<TreeNode>();
        _storeList.AddRange(_storeArray);

        treeView1.BeginUpdate();

        // Delete subnodes
        for (int i = treeView1.Nodes[1].Nodes.Count - 1; i >= 0; i--)
        {
            treeView1.Nodes[1].Nodes.RemoveAt(i);
        }

        treeView1.EndUpdate();

    }
Cadsjo