Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I had a question about filtering tree view and returning just first match.

I've tried to create list<treenode> and change the code. Is it possible improve the below code for finding nodes and child nodes that match my criteria?

private List<TreeNode> FindNodeByValue(TreeNodeCollection nodes, string searchstring)
{

    // Loop through the tree node collection
    List<TreeNode> nodelist=new List<TreeNode>();

    foreach (TreeNode node in nodes)
    {
        // Does the value match the search string?
        if (node.Value.ToUpper().Contains (searchstring.ToUpper()))
            // Yes it does match - return it
            nodelist.Add(node);
        //  return nodelist;
        else
        {
            // No it does not match - search any child nodes of this node
            List<TreeNode> childNode = SearchChildNodes(node, searchstring);
            // If the childNode is not null it was a match
            if (childNode != null)
                // Return the matching node
                return childNode;
        }
    }
    // If the matching node is not found return null
    return null;
}

/// <summary>
/// This method searches a node's ChildNodes collection to find a matching value
/// with the incoming search string
/// It will iteratively call itself as it drills into each nodes child nodes (if present)
/// </summary>
/// <param name="parentNode">Parent node to search for a match</param>
/// <param name="searchstring">string to be matched with the Nodes Value property</param>
/// <returns>Treenode of the matching node if found.  If not found it will be null</returns>
private List<TreeNode> SearchChildNodes(TreeNode parentNode, string searchstring)
{
    List<TreeNode> nodelist2 = new List<TreeNode>();
    // Loop through the child nodes of the parentNode passed in
    foreach (TreeNode node in parentNode.ChildNodes)
    {
        // Does the value match the search string?
        if (node.Value.ToUpper().Contains(searchstring.ToUpper()))
            // Yes it does match - return it
            nodelist2.Add(node);
            //return nodelist2;
            //return node;
        else
        {
            // No it does not match - recursively search any child nodes of this node
            List<TreeNode> childNode = SearchChildNodes(node, searchstring);
            // If the childNode is not null it was a match
            if (childNode != null)
                childNode.Add(node);
                // Return the matching node
                return childNode;
        }
    }
    // If the matching node is not found OR if there were no child nodes then return null
    return null;
}

protected void Button1_Click(object sender, EventArgs e)
{
    TreeNode trnode=FindNodeByValue(TreeView1.Nodes, fieldFilterTxtBx.Text);
    if (trnode != null)
    {
        TreeView1.Nodes.Clear();
       // TreeNode newnode = new TreeNode("Detail Engineering");
       // TreeView1.Nodes.Add(newnode);
        TreeView1.Nodes.Add(trnode);
        TreeView1.ExpandAll();
    }
    else
    {
        Label1.Text = "No file found";
    }
}
share|improve this question

migrated from stackoverflow.com Nov 26 '12 at 15:17

This question came from our site for professional and enthusiast programmers.

1  
if you are trying to match multiple results, you should always check children, you are only doing that if a node does not match which i believe is wrong –  Dany Khalife Nov 26 '12 at 13:10
add comment

2 Answers 2

Currently you do not search sub nodes it a matching parent is found. This code fixes that problem and also simplifies the code by removing the unnecessary SearchChildNodes function.

If you only care about the first match use var node = FindNodeByValue(TreeView1.Nodes, fieldFilterTxtBx.Text).FirstOrDefault();

private IEnumerable<TreeNode> FindNodeByValue(TreeNodeCollection nodes, string searchstring)
{
    foreach (TreeNode node in nodes)
    {
        if (node.Value.IndexOf(searchstring, 
              StringComparison.CurrentCultureIgnoreCase) >= 0)
            yield return node;
        else
        {
            foreach (var subNode in FindNodeByValue(node.ChildNodes, searchstring))
                yield return subNode;
        }
    }
}
share|improve this answer
add comment

To make sure that there will be no out of stack (I'm pretty sure JIT wouldn't be able to optimize out recursive calls through several helper objects built for implementing IEnumerable). Here is small modifications to version of @Magnus:

private IEnumerable<TreeNode> SearchNodesByValue(TreeNodeCollection nodes, string searchstring)
{
    var stack = new Stack<T>(nodes.GetEnumerator());
    try
    {
        do
        {
            var frame = stack.Peek();
            var it = frame.Peek();
            if (!it.MoveNext())
            {
                frame.Pop().Dispose();
                continue;
            }
            var node = it.Current;
            if (node.Value.Contains(searchstring)) yield return node;
            else frame.Push(node.ChildNodes.GetEnumerator());
        } while(stack.Count > 0);
    }
    finally
    {
        // cleanup enumerators
        while(stack.Count > 0) stack.Pop().Dispose();
    }
}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.