8

This function find only first node in treeview, that contains SearchText.

private TreeNode SearchNode(string SearchText,TreeNode StartNode)
{
    TreeNode node=null;
    while (StartNode!= null)
    {
        if (StartNode.Text.ToLower().Contains(SearchText.ToLower()))
        {
            node = StartNode; 
            break;
        };
        if (StartNode.Nodes.Count != 0) 
        {
            node=SearchNode(SearchText, StartNode.Nodes[0]);//Recursive Search
            if (node != null)
            {
                break;
            };
        };
        StartNode = StartNode.NextNode;
    };
    return node;
} 

private void button1_Click(object sender, EventArgs e)
{
    string SearchText = this.textBox1.Text;
    if (SearchText == "")
    {
        return;
    };
    TreeNode SelectedNode = SearchNode(SearchText, treeView1.Nodes[0]);
    if (SelectedNode != null)
    {
        this.treeView1.SelectedNode = SelectedNode;
        this.treeView1.SelectedNode.Expand();
        this.treeView1.Select();
    };
}

How should I change it, so the function will able to find not only the first node, but all of them, every time when I click button1, it'll find next node till the end, and then it starts from the beginning? So I should search not from TreeView1.Nodes[0], but from TreeView1.SelectedNode...

Jackdaw
  • 7,626
  • 5
  • 15
  • 33
Romz
  • 1,437
  • 7
  • 36
  • 63
  • Is this WinForms or ASP.Net? There's two parts to this question, really - finding the nodes, and then displaying them. I suspect this is why the author created the function - it only returns one node so as to expand the tree to that single node. – dash Jul 17 '12 at 21:04
  • This is WinForms. I don't need to display all nodes at the same time, I need to Select nodes by rotation – Romz Jul 17 '12 at 21:16

3 Answers3

16

Something like the following should be fine to add to your Form's code.

    private List<TreeNode> CurrentNodeMatches = new List<TreeNode>();

    private int LastNodeIndex = 0;

    private string LastSearchText;


    private void button1_Click(object sender, EventArgs e)
    {


        string searchText = this.textBox1.Text;
        if (String.IsNullOrEmpty(searchText))
        {
            return;
        };


        if (LastSearchText != searchText)
        {
            //It's a new Search
            CurrentNodeMatches.Clear();
            LastSearchText = searchText;
            LastNodeIndex = 0;
            SearchNodes(searchText, treeView1.Nodes[0]);
        }

        if (LastNodeIndex >= 0 && CurrentNodeMatches.Count > 0 && LastNodeIndex < CurrentNodeMatches.Count)
        {
            TreeNode selectedNode = CurrentNodeMatches[LastNodeIndex];
            LastNodeIndex++;
            this.treeView1.SelectedNode = selectedNode;
            this.treeView1.SelectedNode.Expand();
            this.treeView1.Select();

        }
    } 

    private void SearchNodes(string SearchText, TreeNode StartNode)
    {
        TreeNode node = null;
        while (StartNode != null)
        {
            if (StartNode.Text.ToLower().Contains(SearchText.ToLower()))
            {
                CurrentNodeMatches.Add(StartNode);
            };
            if (StartNode.Nodes.Count != 0)
            {
                SearchNodes(SearchText, StartNode.Nodes[0]);//Recursive Search 
            };
            StartNode = StartNode.NextNode;
        };

    }

There are two parts to this;

  1. Collect all of the nodes into a List<TreeNode>

  2. Page through the List<TreeNode> if the search hasn't changed. If the Search has changed, clear out the list and reset the indexing.

I've tested this with Windows Forms running under .Net 4 - it pages through each node in a TreeView that contain the search text, 1 by 1 until it reaches the last node.

dash
  • 89,546
  • 4
  • 51
  • 71
2

You'll need to create a collection of nodes (like List) and add each found node to that list and return that instead of a single node. Also, you'll have to remove all the break statements

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
  • I don't need to display all nodes at the same time, I need to select only one node at a time, but when I second time click on button1, I need second result's been selected – Romz Jul 17 '12 at 21:20
  • Hmm, no mention of that in the original post ("all of them, every time when I click button1"). In that case, just leave SearchNodes the same, and store the return value somewhere and pass that in as the StartNode argument. (default it to treeView1.Nodes[0])... – Peter Ritchie Jul 17 '12 at 21:29
  • Acctually I don't need to store the return value, I can just write treeView1.SelectedNode ("SelectedNode" is the last result of SearchNode function). But that does't work if the result is derived node, I don't know Why – Romz Jul 17 '12 at 21:36
  • @william Unless someone clicked on another tree view node, in which case you could miss some results. – Peter Ritchie Jul 17 '12 at 21:37
  • @william What do you mean by "derived node"? – Peter Ritchie Jul 17 '12 at 21:37
  • 1
    Also I need to search not from treeView1.SelectedNode, but from treeView1.SelectedNode.NextNode or something like this, because treeView1.SelectedNode is previous result, I already found it. But treeView1.SelectedNode.NextNode might be null – Romz Jul 17 '12 at 21:39
  • I only need last result, by "derived node" I ment not root node – Romz Jul 17 '12 at 21:41
  • I know, I can miss a result, but I only need it to be shown, not store – Romz Jul 17 '12 at 21:50
0

I using this solution for search contains text on tree node

int currentSearch = 0;
int loop = 0;
int found = 0;

private bool FilterTreeNode(TreeNodeCollection nodes, string keyword)
{
    bool result = false;
    for (int i = 0; i < nodes.Count; i++)
    {
        if(result)
            break;
        loop++;
        if (currentSearch < loop)
        {
            currentSearch++;
            if (nodes[i].Text.Contains(keyword))
            {
                found++;
                _treeView.SelectedNode = nodes[i];
                _treeView.SelectedNode.Expand();
                _treeView.SelectedNode.EnsureVisible();
                OnFindResult(string.Format("Current result: {0} on total {1} nodes. FilePath: {2}",
                                    found, _treeView.GetNodeCount(true), nodes[i].Name));
                return true;
            }
        }
        result = FilterTreeNode(nodes[i].Nodes, keyword);
    }

    return result;
}