locked
Check next node? RRS feed

  • Question

  • Hello guys, been awhile since ive been on these forums. Anyway, i have code here that searches through a list and will select the node if the node within the list contains the searched text. Here is my code:

    private void txtfindsong_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Enter)
                {
                    foreach (TreeNode enode in tvsongs.Nodes)
                    {
                        string enodelower = enode.Text.ToLower();
                        string findsong = txtfindsong.Text.ToLower();
    
                        if (enodelower.Contains(findsong))
                        {
                            tvsongs.SelectedNode = enode;
                        }
                    }
    
                    e.SuppressKeyPress = true;
                }         
            }
    Now my question is, with the code above, how can i get it so it will get the first node that matches or contains the selected text, and if i hit enter again, it will go to the next item in the list that also contains the text instead of the same one?

    Thank You!
    OMG, its Joe Ginley!
    Saturday, October 24, 2009 12:52 AM

Answers

  • Well, this code is more in line with what you need.

        private int start_at = 0;
      
        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                for (int i = start_at; i < tvSongs.Nodes.Count; i++)
                {
                    string enodelower = tvSongs.Nodes[i].Text.ToLower();
                    string findsong = txtFindSong.Text.ToLower();

                    if (enodelower.Contains(findsong))
                    {
                        tvSongs.SelectedNode = tvSongs.Nodes[i];
                        start_at = i + 1;
                        if (start_at >= tvSongs.Nodes.Count) start_at = 0;
                        break; // We're done.
                    }
                }

                e.SuppressKeyPress = true;
            }
        }

    But the TreeView's Nodes collection only includes the root nodes. To search deeper in the tree, you need to search each node's Nodes collection to examine the child nodes. Unfortunately that's a lot trickier.

    I think the best approach may be to do a recursive search looking for the node to start searching from. After you find it, continue the search, now looking for the target song.

    (I'm stuck home sick so I'll work on this for a while and let you know if I get it working. Seems like a worthwhile project.)

    Rod
    http://www.vb-helper.com
    • Marked as answer by JoeGinley Sunday, October 25, 2009 7:00 PM
    Sunday, October 25, 2009 6:08 PM

All replies

  • Instead of a foreach, you may instead need to do a for loop so you can specify the index of the first node to search.

    Hope this helps.
    www.insteptech.com ; msmvps.com/blogs/deborahk
    We are volunteers and ask only that if we are able to help you, that you mark our reply as your answer. THANKS!
    Saturday, October 24, 2009 1:10 AM
  • Alright, well how would i use the for statement? I could get the total count of nodes in the list or the total options available? would i declare an int in the for statement or a string? Please help.

    OMG, its Joe Ginley!
    Saturday, October 24, 2009 5:10 AM
  • Well, this code is more in line with what you need.

        private int start_at = 0;
      
        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                for (int i = start_at; i < tvSongs.Nodes.Count; i++)
                {
                    string enodelower = tvSongs.Nodes[i].Text.ToLower();
                    string findsong = txtFindSong.Text.ToLower();

                    if (enodelower.Contains(findsong))
                    {
                        tvSongs.SelectedNode = tvSongs.Nodes[i];
                        start_at = i + 1;
                        if (start_at >= tvSongs.Nodes.Count) start_at = 0;
                        break; // We're done.
                    }
                }

                e.SuppressKeyPress = true;
            }
        }

    But the TreeView's Nodes collection only includes the root nodes. To search deeper in the tree, you need to search each node's Nodes collection to examine the child nodes. Unfortunately that's a lot trickier.

    I think the best approach may be to do a recursive search looking for the node to start searching from. After you find it, continue the search, now looking for the target song.

    (I'm stuck home sick so I'll work on this for a while and let you know if I get it working. Seems like a worthwhile project.)

    Rod
    http://www.vb-helper.com
    • Marked as answer by JoeGinley Sunday, October 25, 2009 7:00 PM
    Sunday, October 25, 2009 6:08 PM
  • I am not the greatest with math which is why i needed a bit help lol. This is exactly what i was looking for. It works like a charm. The only thing i would say is when it hits the last node that contains the text, it wont restart and go through it again. Why is that?
    OMG, its Joe Ginley!
    Sunday, October 25, 2009 7:00 PM
  • I suspect it won't work if you have nested categories because it won't look inside the sub-trees.

    It also doesn't start over because the code doesn't reset start_at and try again. If you do that, then you need another test to break out if you still don't find it.

    (Still working on a better solution. Taking longer than it should.)

    Rod
    http://www.vb-helper.com

    Sunday, October 25, 2009 7:19 PM
  • Ok. This looks like it might work but it's a serious pain. I finally gave up on the recursive solution and just dumped the nodes into a List where they're easier to search.

    I think this handles the "Do you want to search again from the beginning" problem, but you should check it all closely because my brain isn't working too well right now.

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Load TreeView data.
            ... long code omitted ...

            // Select the first node.
            trvOrg.SelectedNode = trvOrg.Nodes[0];

            // Build the node list.
            BuildNodeList();
        }

        // Build a linear list of the nodes.
        // Do this whenever the nodes change.
        private List<TreeNode> node_list;
        private void BuildNodeList()
        {
            node_list = new List<TreeNode>();
            foreach (TreeNode node in trvOrg.Nodes)
            {
                AddNodeAndChildrenToList(node);
            }
        }

        // Add this node and its children to the node list.
        private void AddNodeAndChildrenToList(TreeNode parent)
        {
            // Add the node.
            node_list.Add(parent);

            // Add the children.
            foreach (TreeNode node in parent.Nodes)
            {
                AddNodeAndChildrenToList(node);
            }
        }

        // Search for a string in the node_list.
        private int FindNode(string target, int start_at)
        {
            // If start_at < 0, start at 0.
            if (start_at < 0) start_at = 0;
            for (int i = start_at; i<node_list.Count; i++)
            {
                if (node_list[i].Text.ToLower().Contains(target))
                {
                    // If it's the same node we found last time,
                    // keep searching.
                    if (last_found == i) continue;

                    // Return this node's index.
                    last_found = i;
                    return i;
                }
            }

            return -1;
        }

        // Find the next occurrence of the target string.
        private int last_found = -1;
        private void txtTarget_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                SelectNode(txtTarget.Text.ToLower());
                e.SuppressKeyPress = true;

                txtTarget.Focus();
            }
        }

        // Find and select the next occurrance of this string.
        private void SelectNode(string target)
        {
            // See where we should start looking.
            TreeNode start_node = trvOrg.SelectedNode;
            int start_at;
            if (start_node == null)
            {
                // There is no selected node. Start from the top.
                start_at = -1;
            }
            else
            {
                start_at = node_list.IndexOf(start_node);

                // See if this is the last place we started.
                if (start_at == last_found)
                {
                    // We started here last. Start with the next node.
                    if (++start_at >= node_list.Count) start_at = -1;
                }
            }

            // Search.
            int found_at = FindNode(target, start_at);

            // See if we found it.
            if (found_at >= 0)
            {
                // We found it. Select this node.
                TreeNode found_node = node_list[found_at];
                trvOrg.SelectedNode = found_node;
                last_found = found_at;

                return; // We're done here.
            }

            // We didn't find the target. See if we should
            // try again from the beginning.
            // We started at the beginning. It isn't here.
            // See if we should start over.
            if (MessageBox.Show(
                "The value '" + txtTarget.Text + "' was not found.\n" +
                "Do you want to repeat the search from the beginning?",
                "Not Found",
                MessageBoxButtons.YesNoCancel,
                MessageBoxIcon.Question) == DialogResult.No)
            {
                return; // Bail out.
            }

            // Give it one more try!
            // Search.
            found_at = FindNode(target, start_at);

            // See if we found it.
            if (found_at >= 0)
            {
                // We found it. Select this node.
                TreeNode found_node = node_list[found_at];
                trvOrg.SelectedNode = found_node;
                last_found = found_at;
            }

            // We didn't find the target. Too bad!
            MessageBox.Show(
                "The value '" + txtTarget.Text + "' was not found.\n",
                "Not Found",
                MessageBoxButtons.YesNoCancel,
                MessageBoxIcon.Exclamation);
        }

        // Invalidate the previous last item found.
        // The next time we search, we can begin at the
        // same node instead of the next node.
        private void txtTarget_TextChanged(object sender, EventArgs e)
        {
            last_found = -1;
        }

    Sorry about the length. I'm sure Deborah can find a two-line solution using LINQ ;-)

    In the immortal words of Slurms McKenzie, "I'm gonna go lie down."

    Rod
    http://www.vb-helper.com
    Sunday, October 25, 2009 8:00 PM
  • Ok i fixed it up a bit, it selects a node now, but it will not start from the beginning again and go through the list. Why so?
    OMG, its Joe Ginley!


    EDIT: Ok i realize it does go through the list again, but only if i have like one letter in the search such as e. When i search something such as nickel, i have 3 nodes that contain the item. Once it goes through the 3, it doesnt restart. What could be the reason?
    • Edited by JoeGinley Sunday, October 25, 2009 10:32 PM findings
    Sunday, October 25, 2009 10:20 PM
  • Hi Joe,

    If you email me at RodStephens AT vb-helper.com, I'll mail you the test program I built.

    Rod
    http://www.vb-helper.com
    Sunday, October 25, 2009 10:22 PM
  • Hey with the code above, i switched it up to use it with listviewitem. I am having a problem with this line of code though, what do i do?

    ListViewItem start_listitem = lvlist.SelectedItems[0];
    That line is obviously wrong, but what would i put there?
    OMG, its Joe Ginley!
    Thursday, October 29, 2009 7:48 PM
  • Hi Joe,

    That line should get the first selected item. What are you trying to do?

    Using a ListView should be a lot easier than using a TreeView because it already has a linear structure. You should be able to just loop through it.

    Or if you just want to search the selected items (so the user can select a range to search), you can just look through the SelectedItems collection.


    Rod
    Thursday, October 29, 2009 11:17 PM
  • Sorry i know what i did wrong, thank you!
    OMG, its Joe Ginley!
    Friday, October 30, 2009 12:03 AM