Stackflow and C# newbie here!
I have some code below which loads a list of strings into a treeview control and it works well. The only problem is the speed. When the lists are large it takes time to load, which isn't a problem except it locks up the UI for a while.
So an example would be a list of strings like this (but much larger):
c:\drivers\test1.txt
c:\drivers\test2.txt
c:\drivers\folder\test1.txt
c:\brother\tester\text1.zip
c:\brother\another\text2.zip
c:\data\company1\accounts.rar
c:\data\company2\accounts.rar
The treeview splits the strings using the backslash marker and puts them neatly in a explorer view - this is good!.
tvRestore is the Treeview control in example.
foreach (string path in lstKeys)
{
lastNode = null;
subPathAgg = string.Empty;
foreach (string subPath in path.Split(new string[] { "\\" }, StringSplitOptions.None))
{
foreach (string item in subPath.Split(new string[] { "\\" }, StringSplitOptions.None))
{
if (item == "" || item == null)
{
continue;
}
subPathAgg += item + "\\";
TreeNode[] n = tvRestore.Nodes.Find(subPathAgg, true);
if (n.Length > 0)
{
lastNode = n[0];
continue;
}
else
{
// lastNode = null;
}
TreeNode[] nodes = tvRestore.Nodes.Find(subPathAgg, true);
if (nodes.Length == 0)
if (lastNode == null)
lastNode = tvRestore.Nodes.Add(subPathAgg, item);
else
lastNode = lastNode.Nodes.Add(subPathAgg, item);
else
lastNode = nodes[0];
}
}
}
The only problem is the speed. I tried to use Threads but the code exceptions because the control is on a different Thread. I believe I have to Invoke the Nodes.Add but I can't figure out how to do this.
Ideally the code will start to populate the treeview when the application starts although I don't want the app to lockup for 30-40 seconds or longer for larger lists.
What is the best way to speed this process up?
There are a couple of things you can do, including running this in the background - I like to use Task.Run() for this.
private void Form1_Load(object sender, EventArgs e)
{
// Show the user something
treeView1.Nodes.Add("Loading...");
// Run the tree load in the background
Task.Run(() => LoadTree());
}
Then your Task can build a TreeNode containing all your new nodes and Invoke the TreeView to add the new nodes as a Range, as well as using BeginUpdate...EndUpdate to prevent visual updates until all the nodes are loaded.
private void LoadTree()
{
// Get a list of everything under the users' temp folder as an example
string[] fileList;
DirectoryInfo df = new DirectoryInfo(Path.GetTempPath());
fileList = df.GetFiles("*.*",SearchOption.AllDirectories).Select<FileInfo, string>((f) => f.FullName).ToArray();
// Parse the file list into a TreeNode collection
TreeNode node = GetNodes(new TreeNode(), fileList);
// Copy the new nodes to an array
int nodeCount = node.Nodes.Count;
TreeNode[] nodes = new TreeNode[nodeCount];
node.Nodes.CopyTo(nodes, 0);
// Invoke the treeview to add the nodes
treeView1.Invoke((Action)delegate ()
{
treeView1.BeginUpdate(); // No visual updates until we say
treeView1.Nodes.Clear(); // Remove existing nodes
treeView1.Nodes.AddRange(nodes); // Add the new nodes
treeView1.EndUpdate(); // Allow the treeview to update visually
});
}
This is how I would build the list of TreeNodes.
private TreeNode GetNodes(TreeNode parent, string[] fileList)
{
// build a TreeNode collection from the file list
foreach (string strPath in fileList)
{
// Every time we parse a new file path, we start at the top level again
TreeNode thisParent = parent;
// split the file path into pieces at every backslash
foreach (string pathPart in strPath.Split('\\'))
{
// check if we already have a node for this
TreeNode[] tn = thisParent.Nodes.Find(pathPart, false);
if (tn.Length == 0)
{
// no node found, so add one
thisParent = thisParent.Nodes.Add(pathPart,pathPart);
}
else
{
// we already have this node, so use it as the parent of the next part of the path
thisParent = tn[0];
}
}
}
return parent;
}
On my machine, it takes about 1.5 seconds to load 56,000 nodes into the treeview this way, and the UI is not blocking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With