remarks cref c# .net vb.net treeview recursive-datastructures

c# - cref - poblar vista de árbol de una lista de ruta



remarks c# (8)

Estoy intentando rellenar una vista de árbol de una lista de rutas de carpetas, por ejemplo:

C:/WINDOWS/addins C:/WINDOWS/AppPatch C:/WINDOWS/AppPatch/MUI C:/WINDOWS/AppPatch/MUI/040C C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727 C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/MUI C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/MUI/0409

con una salida como esta:

├───addins ├───AppPatch │ └───MUI │ └───040C ├───Microsoft.NET │ └───Framework │ └───v2.0.50727 │ └───MUI │ └───0409

Observe que no hay ''C: / WINDOWS / Microsoft.NET'' o ''C: / WINDOWS / Microsoft.NET / Framework'' en la lista. He estado trabajando en esto durante casi dos días y hay un montón de errores en mi código. Espero poder obtener ayuda de aquí.

Gracias.

Eric


A menos que publiques el código, es imposible determinar cuál es el problema. En lugar de pasar días en esto, ¿por qué no usar un control de terceros como FolderView


Aquí hay un código muy antiguo que una vez utilicé para crear una vista de árbol ASP.NET a partir del código (asumiendo que TreeView tiene una ID de TreeViewFolders):

protected void Page_Load(object sender, EventArgs e) { GenerateTreeView(@"C:/WINDOWS/"); } private void GenerateTreeView(string rootPath) { GetFolders(System.IO.Path.GetFullPath(rootPath), TreeViewFolders.Nodes); TreeViewFolders.ExpandDepth = 1; } // recursive method to load all folders and files into tree private void GetFolders(string path, TreeNodeCollection nodes) { // add nodes for all directories (folders) string[] dirs = Directory.GetDirectories(path); foreach (string p in dirs) { string dp = p.Substring(path.Length); nodes.Add(Node("", p.Substring(path.Length), "folder")); } // add nodes for all files in this directory (folder) string[] files = Directory.GetFiles(path, "*.*"); foreach (string p in files) { nodes.Add(Node(p, p.Substring(path.Length), "file")); } // add all subdirectories for each directory (recursive) for (int i = 0; i < nodes.Count; i++) { if (nodes[i].Value == "folder") GetFolders(dirs[i] + "//", nodes[i].ChildNodes); } } // create a TreeNode from the specified path, text and type private TreeNode Node(string path, string text, string type) { TreeNode n = new TreeNode(); n.Value = type; n.Text = text; return n; }


Este código llena el control TreeView de los formularios de Windows. Es mucho más simple que las respuestas dadas.

using System; using System.Windows.Forms; using System.IO; // ... private void Form1_Load(object sender, EventArgs e) { treeView1.Nodes.Add(@"C:/"); treeView1.Nodes[0].Tag = @"C:/"; Populate((string)treeView1.Nodes[0].Tag, treeView1.Nodes[0]); } private void Populate(string address, TreeNode rootNode) { DirectoryInfo[] directories = new DirectoryInfo(address).GetDirectories(); foreach (DirectoryInfo directory in directories) { TreeNode newNode = new TreeNode(directory.Name); rootNode.Nodes.Add(newNode); newNode.Tag = directory.FullName; try { DirectoryInfo[] innerDirectories = new DirectoryInfo(directory.FullName).GetDirectories(); if (innerDirectories.Length > 0) newNode.Nodes.Add(new TreeNode()); FileInfo[] innerFiles = new DirectoryInfo(directory.FullName).GetFiles(); if (innerFiles.Length > 0) newNode.Nodes.Add(new TreeNode()); } catch { continue; } } FileInfo[] files = new DirectoryInfo(address).GetFiles(); foreach (FileInfo file in files) rootNode.Nodes.Add(file.Name); } private void treeView1_AfterExpand(object sender, TreeViewEventArgs e) { if (e.Node.Nodes.Count < 3) { e.Node.Nodes.Clear(); Populate((string)e.Node.Tag, e.Node); } }


Tomé su código, y funciona muy bien, pero hice solo una pequeña modificación para mejorar la velocidad de carga cuando se usa con una gran lista de archivos, parece una operación de búsqueda, y las operaciones de cadenas generalmente son muy lentas

private TreeNode PopulateTreeNode2(string[] paths, string pathSeparator) { if (paths == null) return null; TreeNode thisnode = new TreeNode(); TreeNode currentnode; char[] cachedpathseparator = pathSeparator.ToCharArray(); foreach (string path in paths) { currentnode = thisnode; foreach (string subPath in path.Split(cachedpathseparator)) { if (null == currentnode.Nodes[subPath]) currentnode = currentnode.Nodes.Add(subPath, subPath); else currentnode = currentnode.Nodes[subPath]; } } return thisnode; }

entonces puedes usar:

string[] paths = { @"C:/WINDOWS/AppPatch/MUI/040C", @"D:/WINDOWS/Microsoft.NET/Framework/v2.0.50727", @"E:/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" }; TreeView treeview = new TreeView(); treeview.Nodes.Add(PopulateTreeNode2(paths, "//"));

NOTA: tal vez sea necesario un cierto control de sensibilidad de la cadena en ambas soluciones, para evitar que se vuelvan a crear algunas carpetas.

porque alguna url podría estar apuntando a la misma carpeta en el disco pero deletreada de manera diferente, como: Windows; WinDOWs, WINDOWS


ehosca responde a correcr, pero hay un pequeño problema, cuando cambio de ruta para que me guste

C:/WINDOWS/AppPatch/MUI/040C D:/WIS/Microsoft.NET/Framework/v2.0.50727 E:/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

Se llenará de árboles como este.

Pero añadiendo algún código extra podemos evitar esta situación. Así que cambié el código en PopulateTreeView

private static void PopulateTreeView(TreeView treeView, 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]; } lastNode = null; // This is the place code was changed } }

Ahora funciona bien así


para una versión linq''y:

public static TreeNode MakeTreeFromPaths(List<string> paths, string rootNodeName = "", char separator = ''/'') { var rootNode = new TreeNode(rootNodeName); foreach (var path in paths.Where(x => !string.IsNullOrEmpty(x.Trim()))) { var currentNode = rootNode; var pathItems = path.Split(separator); foreach (var item in pathItems) { var tmp = currentNode.Nodes.Cast<TreeNode>().Where(x => x.Text.Equals(item)); currentNode = tmp.Count() > 0 ? tmp.Single() : currentNode.Nodes.Add(item); } } return rootNode; }


private void Form2_Load(object sender, EventArgs e) { treeView1.CheckBoxes = true; foreach (TreeNode node in treeView1.Nodes) { node.Checked = true; } string[] drives = Environment.GetLogicalDrives(); foreach (string drive in drives) { // treeView1.Nodes[0].Nodes[1].Checked = true; DriveInfo di = new DriveInfo(drive); int driveImage; switch (di.DriveType) { case DriveType.CDRom: driveImage = 3; break; case DriveType.Network: driveImage = 6; break; case DriveType.NoRootDirectory: driveImage = 8; break; case DriveType.Unknown: driveImage = 8; break; default: driveImage = 2; break; } TreeNode node = new TreeNode(drive.Substring(0, 1), driveImage, driveImage); node.Tag = drive; if (di.IsReady == true) node.Nodes.Add("..."); treeView1.Nodes.Add(node); } foreach (TreeNode node in treeView1.Nodes) { node.Checked = true; } } private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e) { { if (e.Node.Nodes.Count > 0) { if (e.Node.Nodes[0].Text == "..." && e.Node.Nodes[0].Tag == null) { e.Node.Nodes.Clear(); string[] dirs = Directory.GetDirectories(e.Node.Tag.ToString()); foreach (string dir in dirs) { DirectoryInfo di = new DirectoryInfo(dir); TreeNode node = new TreeNode(di.Name, 0, 1); node.Checked = true; try { node.Tag = dir; if (di.GetDirectories().Count() > 0) node.Nodes.Add(null, "...", 0, 0).Checked = node.Checked; } catch (UnauthorizedAccessException) { node.ImageIndex = 12; node.SelectedImageIndex = 12; } catch (Exception ex) { MessageBox.Show(ex.Message, "DirectoryLister", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { node.Checked = e.Node.Checked; e.Node.Nodes.Add(node); } } } } } } private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) { button1.Enabled = false; TreeNode node = e.Node; bool is_checked = node.Checked; foreach (TreeNode childNode in e.Node.Nodes) { childNode.Checked = e.Node.Checked; } treeView1.SelectedNode = node; }


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