Elixir
Elixir

Reputation: 287

How to show All drive's related data/folders in a treeview?

 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

Answers (1)

rene
rene

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.

Background worker

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;
}

Drive folder traversal

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

Related Questions