The OP here expressed the goal of finding any TreeNode in a TreeView without recursion, or some form of iteration: that is
impossible. What is possible is to minimize the computation involved in searching for TreeNodes by building a "flattened" list of the Nodes. That technique is illustrated here.
When you execute code like treeView1.Nodes.ContainsKey("node key"); you search only the specific TreeNodeCollection of either the TreeView, or a Node in the TreeView. The 'IndexOfKey method works in the same way.
Beginning with FrameWork 2.0, the 'Find operator was implemented: this is a method of the TreeNodeCollection Class that takes a string which is the Name/Key of a Node, and a second, boolean, parameter which, if true, will search recursively through all the sub-nodes.
So, to search the entire TreeView for a TreeNode with the Key "Node14," you can call: treeView1.Nodes.Find("Node14", true). When you perform such a search, you trigger the
internal recursive iteration of the underlying data structure, the TreeNodeCollections, and TreeNodes, of the TreeView.
To create a "flattened" list of all TreeNodes, and update that list whenever a TreeNode is added, or deleted, to the Tree:
private List<TreeNode> flatNodeList = new List<TreeNode>();
private void createFlatList(TreeNodeCollection theNodes)
{
foreach (TreeNode theNode in theNodes)
{
flatNodeList.Add(theNode);
if(theNode.Nodes.Count != 0) createFlatList(theNode.Nodes);
}
}
private void Form1_Load(object sender, EventArgs e)
{
createFlatList(treeView1.Nodes);
}
Once you have that List of all TreeNodes, you can search it, and use all the regular generic List operators; you can use Linq on it to do complex queries, and analysis, and select sub-sets of nodes based on conditions, etc.
That leaves the question of how you update the flat-list as the user adds, or deletes, nodes at run-time; obviously you don't want to re-build the entire list recursively every time a single node is added, or deleted !
One way to update is to define your own methods for add, and delete, TreeNodes:
private void AddNode(TreeNodeCollection theNodes, string key)
{
TreeNode newNode = new TreeNode(key);
flatNodeList.Add(newNode);
theNodes.Add(newNode);
}
private void DeleteNode(TreeNode theNode)
{
if(! flatNodeList.Contains(theNode)) throw new KeyNotFoundException("Invalid Node in DeleteNode");
flatNodeList.Remove(theNode);
if (theNode.Level == 0)
{
theNode.TreeView.Nodes.Remove(theNode);
}
else
{
theNode.Parent.Nodes.Remove(theNode);
}
}
You can take the principles demonstrated here and use them to add other methods that might update the flat list, like 'AddRange.
Note: not every application using the standard TreeView might benefit ... much ... from avoiding using the 'Find operator to search by the techniques shown here. However, there are many other possible uses for a flattened list of all the Nodes.
If I were using a TreeView with an extremely large number of TreeNodes, deeply nested, with frequent need to do searches, I would certainly use the techniques shown here.
In some real applications I have written, not only have I created a flattened list of TreeNodes, I've created a data structure of the form Dictionary<int,List<treenode>>> ... this is built dynamically in the same recursive way I build a flattened List of all the TreeNodes, and ends up containing a separate TreeNodeCollection for nodes at each level in the TreeView.
Other techniques you can use include sub-classing the WinForms TreeView, and over-riding the methods you need to modify to keep a flattened list updated.