8

Im working with file systems and I have a List<> of file objects that have the file path as a property. Basically I need to create a treeview in .NET but im struggling to think of the best way to go about doing this as I need to create a tree structure from a list like:

C:/WINDOWS/Temp/ErrorLog.txt
C:/Program Files/FileZilla/GPL.html
C:/Documents and Settings/Administrator/ntuser.dat.LOG

etc....

The list is not structured at all and I cant make any changes to the current object structure.

I'm working in C#.

Many thanks for all who contribute

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
user31849
  • 103
  • 1
  • 1
  • 6
  • Possible duplicate of [populate treeview from a list of path](http://stackoverflow.com/questions/1155977/populate-treeview-from-a-list-of-path) – FH-Inway Aug 07 '16 at 06:11

5 Answers5

16

If you wanted to stick with the strings something like this would work...

TreeNode root = new TreeNode();
TreeNode node = root;
treeView1.Nodes.Add(root);

 foreach (string filePath in myList) // myList is your list of paths
 {
    node = root;
    foreach (string pathBits in filePath.Split('/'))
    {
      node = AddNode(node, pathBits);
    }
 }


private TreeNode AddNode(TreeNode node, string key)
{
    if (node.Nodes.ContainsKey(key))
    {
        return node.Nodes[key];
    }
    else
    {
        return node.Nodes.Add(key, key);
    }
}
PaulB
  • 20,984
  • 13
  • 54
  • 75
  • this is b-e-a-utiful! Thankyou very much kind sir! – user31849 Mar 25 '09 at 15:13
  • Awesome; exactly what I needed. The only change I needed to make was to change `filePath.Split('/')` to `filePath.Split('/', StringSplitOptions.RemoveEmptyEntries)` for my purposes. Thank you! – Owen Blacker Aug 05 '12 at 01:24
4

I would turn the string into a FileInfo.

Once you have the FileInfo object, you can use the Directory property to retrieve the DirectoryInfo for each path.

Once you have the DirectoryInfo for the path, it's easy to "walk up" the Parent reference in DirectoryInfo to turn each path into a list of directories + filename - ie:

{"C:","Windows","Temp","ErrorLog.txt"}

This should be fairly straightforward to insert into your treeview. Just look for each section of the path in turn, and if it doesn't exist, add it....

Reed Copsey
  • 522,342
  • 70
  • 1,092
  • 1,340
2
    private void Form1_Load(object sender, EventArgs e)
    {
        var paths = new List<string>
                        {
                            @"C:\WINDOWS\AppPatch\MUI\040C",
                            @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727",
                            @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI",
                            @"C:\WINDOWS\addins",
                            @"C:\WINDOWS\AppPatch",
                            @"C:\WINDOWS\AppPatch\MUI",
                            @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI\0409"
                        };
        treeView1.PathSeparator = @"\";
        PopulateTreeView(treeView1, paths, '\\');
    }

    private static void PopulateTreeView(TreeView treeView, IEnumerable<string> paths, char pathSeparator)
    {
        TreeNode lastNode = null;
        string subPathAgg;
        foreach (string path in paths)
        {
            subPathAgg = string.Empty;
            foreach (string subPath in path.Split(pathSeparator))
            {
                subPathAgg += subPath + pathSeparator;
                TreeNode[] nodes = treeView.Nodes.Find(subPathAgg, true);
                if (nodes.Length == 0)
                    if (lastNode == null)
                        lastNode = treeView.Nodes.Add(subPathAgg, subPath);
                    else
                        lastNode = lastNode.Nodes.Add(subPathAgg, subPath);
                else
                    lastNode = nodes[0];
            }
        }
    }

alt text

ehosca
  • 897
  • 7
  • 16
2

give recursion a try.

private void AddFiles()
{
  // Iterate your list with FileInfos here
  foreach( var fileInfo in new Collection<FileInfo>() )
  {
    GetOrCreateTreeNode( fileInfo.Directory ).Nodes.Add( new TreeNode( fileInfo.Name ) );
  }
}

private TreeNode GetOrCreateTreeNode( DirectoryInfo directory )
{
  if( directory.Parent == null )
  {
    // Access your TreeView control here:
    var rootNode = <TreeView>.Nodes[directory.Name];
    if( rootNode == null )
    {
      rootNode = new TreeNode(directory.Name);
      // Access your TreeView control here:
      <TreeView>.Nodes.Add( rootNode );
    }
    return rootNode;
  }

  var parent = GetOrCreateTreeNode( directory.Parent );
  var node = parent.Nodes[directory.Name];
  if( node == null )
  {
    node = new DirectoryNode( directory );
    parent.Nodes.Add( node );
  }
  return node;
}

This code should give you only an idea - I have to admit that I did not test it before posting here.

tanascius
  • 50,043
  • 21
  • 106
  • 130
  • In the GetOrCreateTreeNode method, what is the Directories.Nodes[directory.Name] line meant to be? As there is no such thing as Directories.... Your help so far is very much appreciated! – user31849 Mar 23 '09 at 17:09
  • Thankyou, i thought it would be that but I wanted to make sure – user31849 Mar 23 '09 at 17:19
0

EHosca's piece worked for me perfectly, with one change - I had to set lastnode to nothing after the foreach path in paths area.

This is eHosca's code above, ported to VB.

Private Sub PopulateTreeView(tv As TreeView, paths As List(Of String), pathSeparator As Char)
    Dim lastnode As TreeNode = Nothing
    Dim subPathAgg As String
    For Each path In paths
        subPathAgg = String.Empty
        lastnode = Nothing
        For Each subPath In path.Split(pathSeparator)
            subPathAgg += subPath + pathSeparator
            Dim nodes() As TreeNode = tv.Nodes.Find(subPathAgg, True)
            If nodes.Length = 0 Then
                If IsNothing(lastnode) Then
                    lastnode = tv.Nodes.Add(subPathAgg, subPath)
                Else
                    lastnode = lastnode.Nodes.Add(subPathAgg, subPath)
                End If
            Else
                lastnode = nodes(0)
            End If
        Next
    Next
End Sub
John
  • 11
  • 2