Reputation: 287
cmbDrives.DataSource = Environment.GetLogicalDrives();
I have this code to show all drives in combobox, and want to show All Drive's related data in treeview
on comboboxselectionchanged
event.
How can I do that?
Upvotes: 0
Views: 861
Reputation: 42434
The following code achieves what you want by leveraging a backgroundworker to make sure the UI stays responsive while progress is made during the folder traversal.
First add a ComboBox, a Treeview and a BackgroundWorker to your design surface. Make sure to add the events used in the following code from the Properties window for each control using the eventview. Make sure to set the property WorkerReportsProgress
to true for the BackgroundWorker.
First the ComboBox SelectionIndexChanged event:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
this.comboBox1.Enabled = false;
this.backgroundWorker1.RunWorkerAsync(comboBox1.SelectedItem.ToString());
}
We disable our combobox to prevent selecting a new value while we are handling a drive traversal. Then we start our BackgroundWorker passing it the SelectedItem which we assume is a valid drive.
The DoWork event takes an eventargs that has an Argument property that contain the value we provided with calling RunWorkerAsync. As we our now on a non-UI thread we need some trickery to update the UI. The background worker can do that with its ReportProgress method. It takes an integer, normally used for how far we are and an optional userstate. We use those two to indicate which state we are in and provide a TreeNode that needs be added or updated on our TreeView. It then call GetDirectoryNodes
to do the directory traversal.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
TreeNode node = new TreeNode(e.Argument.ToString());
backgroundWorker1.ReportProgress(0, node);
GetDirectoryNodes(e.Argument.ToString(), node);
}
ProgressChanged is called every time we have a TreeNode (or Tuple of TreeNodes) so we can add nodes to the TreeView or one of its nodes while we are at the UI thread. The ProgressPercentage
is not used to show how far we are but to distinguish between the initial state and the traversal state.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
switch (e.ProgressPercentage)
{
case 0:
// we have s TreeNode, this is our root.
treeView1.Nodes.Add((TreeNode) e.UserState);
break;
case 1:
// we get a tuple, the parent and it's intended child.
var tup = (Tuple<TreeNode,TreeNode>) e.UserState;
tup.Item1.Nodes.Add(tup.Item2);
break;
default:
break;
}
}
Once we are done (that is every folder is traversed) we enable the combobox again so we can select a new drive.
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.comboBox1.Enabled = true;
}
To traverse a directory tree I use a recursive function (loosely inspired on the answer from Chris Ballard that calls the BackgroundWorkers ReportProgress
method once it has TreeNode that is ready to be added to the TreeView. Notice how I use a Tuple as a state object that holds the Parent and the Child to be added but that specific action is left for the ProgressChanged event on UI-Thread.
private void GetDirectoryNodes(string path, TreeNode node)
{
try
{
var subDirs = Directory.GetDirectories(path);
foreach (string p in subDirs)
{
var subnode = new TreeNode(p);
backgroundWorker1.ReportProgress(
1,
new Tuple<TreeNode, TreeNode>(
node, subnode
));
GetDirectoryNodes(p, subnode); // recursive!
}
}
catch (Exception exp)
{
var subnode = new TreeNode(path+"\\error");
subnode.ToolTipText = exp.Message;
backgroundWorker1.ReportProgress(
1,
new Tuple<TreeNode, TreeNode>(
node, subnode
));
}
}
Upvotes: 1