remplir treeview à partir d'une liste de chemin
j'essaye de peupler une vue d'arbre à partir d'une liste de chemin de dossier, par exemple:
C:WINDOWSaddins
C:WINDOWSAppPatch
C:WINDOWSAppPatchMUI
C:WINDOWSAppPatchMUI0C
C:WINDOWSMicrosoft.NETFrameworkv2.0.50727
C:WINDOWSMicrosoft.NETFrameworkv2.0.50727MUI
C:WINDOWSMicrosoft.NETFrameworkv2.0.50727MUI09
avec une sortie comme ceci:
├───addins
├───AppPatch
│ └───MUI
│ └───040C
├───Microsoft.NET
│ └───Framework
│ └───v2.0.50727
│ └───MUI
│ └───0409
attention il n'y a pas de "C:WINDOWSMicrosoft.NET" ou "C:WINDOWSMicrosoft.NETFramework dans la liste. J'y travaille depuis presque deux jours et il y a un tas de bugs dans mon code. J'espère que je peux avoir de l'aide d'ici.
Merci.
Eric
8 réponses
private void Form1_Load(object sender, EventArgs e)
{
var paths = new List<string>
{
@"C:\WINDOWS\AppPatch\MUI0C",
@"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\MUI09"
};
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];
}
}
}
réponse d'ehosca correcte, mais il y a un petit problème, quand j'ai changer les chemins d'accès à comme ceci
C:\WINDOWS\AppPatch\MUI0C
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\MUI09
il va popoulate treeview comme ceci.
mais en ajoutant un peu de code supplémentaire nous pouvons éviter cette situation. J'ai donc changé le code dans Populatetreview
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
}
}
Maintenant il fonctionne très bien comme ceci
pour une version 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;
}
j'ai pris votre code, et ça marche très bien, mais j'ai juste fait une petite modification pour améliorer la vitesse de charge lorsqu'il est utilisé avec une grande liste de fichiers il semble que l'opération find, et les opérations string sont généralement très lentes
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;
}
ensuite, vous pouvez utiliser:
string[] paths = {
@"C:\WINDOWS\AppPatch\MUI0C",
@"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\MUI09"
};
TreeView treeview = new TreeView();
treeview.Nodes.Add(PopulateTreeNode2(paths, "\"));
NOTE: peut-être qu'une vérification de la sensibilité de la chaîne de caractères sera nécessaire dans les deux solutions,
afin de prévenir certains dossiers ré créations.
parce qu'une url pourrait être pointant vers le même dossier sur le disque mais épelé différent tel que: Windows; WinDOWs, WINDOWS
voici un très vieux code que j'ai utilisé une fois pour créer ASP.NET treeview from code (en supposant que TreeView a un 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;
}
ce code alimente le contrôle TreeView des formulaires windows. Il est beaucoup plus simple que les réponses données.
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);
}
}
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;
}
sauf si vous postez le code, il est impossible de déterminer ce qui ne va pas avec lui. Au lieu de passer des jours sur ce pourquoi ne pas utiliser un contrôle tiers tel que le dossier partagé sommaire