Sunday, June 3, 2012

Promoting/Demoting, Moving Up and Down, nodes in the TreeView Control [C#]

I had a difficult time finding the answers to these situations that I needed to implement, and when there is more than one of the same slip in the basket, that same slip will have a higher chance of being found. So, if there are already working answers for these out there, then this post will increase the chances of success in finding these answers to another questioner like me before.

Knowing me I like to get strait to the point and not read about how it works or why and where it would be used first. I like to see the raw [working] code first, then evaluate and implement it. I feel it saves me some time in a sense... So:
To move a node up and down within it's parent node, the following code would be used: (as found here)

public static class Extensions
{
    public static void MoveUp(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        TreeView view = node.TreeView;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index > 0)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index - 1, node);
            }
        }
        else if (node.TreeView.Nodes.Contains(node)) //root node
        {
            int index = view.Nodes.IndexOf(node);
            if (index > 0)
            {
                view.Nodes.RemoveAt(index);
                view.Nodes.Insert(index - 1, node);
            }
        }
    }

    public static void MoveDown(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        TreeView view = node.TreeView;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index < parent.Nodes.Count -1)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index + 1, node);
            }
        }
        else if (view != null && view.Nodes.Contains(node)) //root node
        {
            int index = view.Nodes.IndexOf(node);
            if (index < view.Nodes.Count - 1)
            {
                view.Nodes.RemoveAt(index);
                view.Nodes.Insert(index + 1, node);
            }
        }
    }
}


...though I don't know if they actually work as I have not yet tested them. But I did write and test some methods of my own that do the same job and I know for a fact that they work (up to the root node only). However, I'm not sure if they are efficient at doing their jobs:... (So if the above doesn't work, you could resort to the one bellow or attempt to write your own (Or keep searching till you find what your looking for))

        private void btnDown_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView.SelectedNode;
            if (treeView.SelectedNode.Parent != null)
            {
                TreeNodeCollection collection = treeView.SelectedNode.Parent.Nodes;
                treeView.SelectedNode = treeView.SelectedNode.Parent;
                int index = collection.IndexOf(node);
                collection.RemoveAt(index);
                collection.Insert(index - 1, node);
                List<TreeNode> nodes = new List<TreeNode>();
                foreach (TreeNode tree in collection) nodes.Add(tree);
                treeView.SelectedNode.Nodes.Clear();
                treeView.SelectedNode.Nodes.AddRange(nodes.ToArray());
                treeView.SelectedNode = node;
            }
        }
        private void btnUp_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView.SelectedNode;
            if (treeView.SelectedNode.Parent != null)
            {
                TreeNodeCollection collection = treeView.SelectedNode.Parent.Nodes;
                treeView.SelectedNode = treeView.SelectedNode.Parent;
                int index = collection.IndexOf(node);
                collection.RemoveAt(index);
                collection.Insert(index + 1, node);
                List<TreeNode> nodes = new List<TreeNode>();
                foreach (TreeNode tree in collection) nodes.Add(tree);
                treeView.SelectedNode.Nodes.Clear();
                treeView.SelectedNode.Nodes.AddRange(nodes.ToArray());
                treeView.SelectedNode = node;
            }
        }


Now, when it comes to promoting or demoting nodes, that is a hard problem to find an answer to via source code online. I have spent a good 3-5hrs just trying to find an efficient answer if even an answer. What I came up with were description-only routines, other's comments of there success, or job-related topics where employees can be 'promoted'. Alright, unless you have some luck finding a better solution to this matter, here is my working code: (up to the root node only)

        private void btnPremote_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView.SelectedNode;
            if (treeView.SelectedNode.Parent != null)
            {
                if (treeView.SelectedNode.Parent.Parent != null)
                {
                    TreeNodeCollection collection = treeView.SelectedNode.Parent.Nodes;
                    TreeNodeCollection collection2 = treeView.SelectedNode.Parent.Parent.Nodes;

                    treeView.SelectedNode = treeView.SelectedNode.Parent;
                    int index = collection.IndexOf(node);
                    collection.RemoveAt(index);
                    collection2.Insert(collection2.Count, node);

                    List<TreeNode> nodes = new List<TreeNode>();
                    foreach (TreeNode tree in collection2) nodes.Add(tree);
                    treeView.SelectedNode = treeView.SelectedNode.Parent;
                    treeView.SelectedNode.Nodes.Clear();
                    treeView.SelectedNode.Nodes.AddRange(nodes.ToArray());
                    treeView.SelectedNode = node;
                }
            }
        }
        private void btnDemote_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView.SelectedNode;
            if (treeView.SelectedNode.Parent != null)
            {
                if (treeView.SelectedNode.Parent != null)
                {
                    if (treeView.SelectedNode.Parent.Nodes.Count > 1 
                        && treeView.SelectedNode.PrevNode != null)
                    {
                        treeView.SelectedNode = treeView.SelectedNode.PrevNode;
                        TreeNodeCollection collection = treeView.SelectedNode.Nodes;
                        collection.Remove(node);
                        collection.Insert(collection.Count, node);

                        List<TreeNode> nodes = new List<TreeNode>();
                        foreach (TreeNode tree in collection) nodes.Add(tree);
                        treeView.SelectedNode.Nodes.Clear();
                        treeView.SelectedNode.Nodes.AddRange(nodes.ToArray());
                        treeView.SelectedNode = node;
                    }
                }
            }
        }



So, there you have it!
Looking at the code presented on the post from StackOverflow, I see implementations that could be made to my code to remove the 'up to root node only' statement; I will not implement it this time as it is not needed in my current project... but maybe another time.