My code has a function that scans a root directory and showing txt files (for example) in a TreeView
:
private TreeNode DirectoryToTreeView(TreeNode parentNode, string path,
string extension = ".txt")
{
var result = new TreeNode(parentNode == null ? path : Path.GetFileName(path));
foreach (var dir in Directory.GetDirectories(path))
{
TreeNode node = DirectoryToTreeView(result, dir);
if (node.Nodes.Count > 0)
{
result.Nodes.Add(node);
}
}
foreach (var file in Directory.GetFiles(path))
{
if (Path.GetExtension(file).ToLower() == extension.ToLower())
{
result.Nodes.Add(Path.GetFileName(file));
}
}
return result;
}
This function should by called from the button like:
treeView1.Nodes.Add(DirectoryToTreeView(null, @"C:\Users\Tomer\Desktop\a"));
Its obviously freezing the UI.
I am new to this and I have searched the web and nothing seemed relevant to my problem because no one used recursive function and I cant simply call BeginInvoke
on the entire function because it will have no effect.
What path should I take? Maybe change the function to work with a while loop and then calling BeginInvoke
inside the if statements? Creating a TreeNode
object in memory to populate (which may be too large)?
You could convert the DirectoryToTreeNode
method to an asynchronous method, and offload any blocking I/O operation to the ThreadPool
, by using the Task.Run
method:
private async Task<TreeNode> DirectoryToTreeNodeAsync(string path,
TreeNode parentNode = null)
{
var node = new TreeNode(parentNode == null ? path : Path.GetFileName(path));
string[] subdirectories = await Task.Run(() => Directory.GetDirectories(path));
foreach (string dirPath in subdirectories)
{
TreeNode childNode = await DirectoryToTreeNodeAsync(dirPath, node);
node.Nodes.Add(childNode);
}
string[] files = await Task.Run(() => Directory.GetFiles(path));
foreach (string filePath in files)
{
node.Nodes.Add(Path.GetFileName(filePath));
}
return node;
}
Notice that no UI control is touched while running on the ThreadPool
(inside the Task.Run
delegate). All UI controls should be manipulated exclusively by the UI thread.
Usage example:
private async void Button1_Click(object sender, EventArgs e)
{
Button1.Enabled = false;
Cursor = Cursors.WaitCursor;
try
{
TreeView1.Nodes.Clear();
TreeView1.Nodes.Add(
await DirectoryToTreeNodeAsync(@"C:\Users\Tomer\Desktop\a"));
}
finally
{
Cursor = Cursors.Default;
Button1.Enabled = true;
}
}