1

I'm trying to search a TreeView for a particular string, once I have found the index of the node, I wish to return its index and change the back color of that particular node, however my current code does not seem to be returning any matches, unless it's the root node:

    private void ApplyRulesetColors()
    {
        foreach (var rule in dictOverwriteEntries)
        {
            int iResultIndex = SearchTreeView(rule.Key, tvDirectoryStructure.Nodes);

            if (iResultIndex > -1)
            {
                switch (rule.Value)
                {
                    case Operations.Overwrite:
                        tvDirectoryStructure.Nodes[iResultIndex].BackColor = Color.Red;
                        break;
                    case Operations.Delete:
                        break;
                    case Operations.None:
                        break;
                    default:
                        break;
                }
            }
        }
    }

This is the function that should be searching the treeview:

    private int SearchTreeView(string p_sSearchTerm, TreeNodeCollection p_Nodes)
    {
        foreach (TreeNode node in p_Nodes)
        {
            if (node.Text == p_sSearchTerm)
            {
                return node.Index;
            }

            if (node.Nodes.Count > 0)
                SearchTreeView(p_sSearchTerm, node.Nodes);
        }

        return -1;
    }

At the moment that will only ever match on the root node value and return 0, even though (as far as I can tell) it should be searching through the entire tree including child nodes.

Thank you.

  • 2
    wouldnt you want "return SearchTreeView(p_sSearchTerm, node.Nodes);" ? otherwise it eats the return value – BugFinder Feb 17 '17 at 10:14
  • 1
    You can use [`Find`](https://msdn.microsoft.com/en-us/library/system.windows.forms.treenodecollection.find(v=vs.110).aspx) method of `TreeView` to find nodes based on their `Name` property. Also if you want to perform a more complicated search, you can use [`Descendants`](http://stackoverflow.com/a/32360956/3110834) extension method. You can see an example of both methods [here](http://stackoverflow.com/a/34228733/3110834). – Reza Aghaei Feb 17 '17 at 11:41

2 Answers2

3

There are two problems in your code:

  1. You don't return the result of the recursive call, but -1 if the node was not found in the root node's children.
  2. You return the nodes Index, which is the index in the node's parent children collection, not a global index.

I suggest to return the TreeNode itself instead. Change your method like that:

private TreeNode SearchTreeView(string p_sSearchTerm, TreeNodeCollection p_Nodes)
{
    foreach (TreeNode node in p_Nodes)
    {
        if (node.Text == p_sSearchTerm)
            return node;

        if (node.Nodes.Count > 0)
        {
            TreeNode child = SearchTreeView(p_sSearchTerm, node.Nodes);
            if (child != null) return child;
        }
    }

    return null;
}

And use it like that:

 private void ApplyRulesetColors()
 {
    foreach (var rule in dictOverwriteEntries)
    {
        TreeNode resultNode = SearchTreeView(rule.Key, tvDirectoryStructure.Nodes);

        if (resultNode != null)
        {
            switch (rule.Value)
            {
                case Operations.Overwrite:
                    resultNode.BackColor = Color.Red;
                    break;
                case Operations.Delete:
                    break;
                case Operations.None:
                    break;
                default:
                    break;
            }
        }
   }
}

Note however that this code will only find the first matching node. I don't know if your tree may contain multiple nodes with the same Text. In that case you should use another property to identify the node.

Community
  • 1
  • 1
René Vogt
  • 43,056
  • 14
  • 77
  • 99
2

You need to return TreeNode itself not it's index, as the index is relative to the parent of located node. Also, your recursive SearchTreeView doesn't return an element when it found it during recursive call. The code below will work and return TreeNode itself, which you can style as you wish.

You may wish to know that your approach is not efficient, as you need to iterate the tree as many times as you have rules in your list. It may be more efficient if you iterate the tree once, and then match rules for each node in the list. Your code may be a good case to apply Visitor pattern: http://www.dofactory.com/net/visitor-design-pattern

Any way, here is a correct SearchTreeView:

private TreeNode SearchTreeView(string p_sSearchTerm, TreeNodeCollection p_Nodes)
{
    foreach (TreeNode node in p_Nodes)
    {
        if (node.Text == p_sSearchTerm)
        {
            return node;
        }

        if (node.Nodes.Count > 0)
        {
            var result = SearchTreeView(p_sSearchTerm, node.Nodes);
            if (result != null)
            {
                return result;
            }
        }
    }

    return null;
}
zmechanic
  • 1,842
  • 21
  • 27