我正在尝试从文件夹路径列表填充树视图,例如:
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
输出如下:
├───addins
├───AppPatch
│ └───MUI
│ └───040C
├───Microsoft.NET
│ └───Framework
│ └───v2.0.50727
│ └───MUI
│ └───0409
请注意,列表中没有“C:\WINDOWS\Microsoft.NET”或“C:\WINDOWS\Microsoft.NET\Framework”。我已经为此工作了近两天,我的代码中有很多错误。希望我能从这里得到帮助。
谢谢。
埃里克
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];
}
}
}
对于 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;
}
ehosca 答案是正确的,但有一个小问题, 当我将路径更改为这样时
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
它将像这样填充树视图。
但是添加一些额外的代码我们可以避免这种情况。所以我改变了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
}
}
现在这样就可以正常工作了
我拿了你的代码,它运行得很好, 但我只是做了一点修改来提高加载速度 当它用于大量文件列表时 看起来像是find操作,而字符串操作一般都很慢
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;
}
然后你可以使用:
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, "\\"));
注意:两种解决方案中可能都需要一些字符串敏感性检查,
为了防止重新创建某些文件夹。
因为某些 url 可能指向磁盘上的同一文件夹
但拼写不同,例如:
窗户;窗口,窗口
这是我曾经用来从代码创建 ASP.NET 树视图的一些非常旧的代码(假设 TreeView 的 ID 为 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;
}
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;
}
我已经成功地仅使用
for
循环从路径列表创建了一棵树。看起来这是目前这个问题最简单的答案。
使用此代码块创建一棵树。
list
是文件或文件夹的列表,treeView1
是您的 TreeView。
//Creates a tree from given path list
foreach (string path in list)
{
TreeNodeCollection nodes = treeView1.Nodes;
foreach (string path_part in path.Split('\\'))
{
//Here it adds a new node (file or folder)
if (!nodes.ContainsKey(path_part))
nodes.Add(path_part, path_part);
//Go one node deeper
nodes = nodes[path_part].Nodes;
}
}
注意 - 如果您将其与以路径分隔符开头的路径一起使用(例如
/home/user
),这可能会中断
如果您想删除路径的公共部分(或删除单个父节点),请在前一个代码块之后使用此代码块:
//This removes "single" TreeNodes (common paths)
while (treeView1.Nodes.Count == 1)
{
//This "unpacks" child TreeNodes from the only parent TreeNode
for (int i = 0; i < treeView1.Nodes[0].Nodes.Count; i++)
treeView1.Nodes.Add(treeView1.Nodes[0].Nodes[i]);
//This removes parent TreeNode
treeView1.Nodes.RemoveAt(0);
}
如果所有路径都相同,这将生成一棵空树。
我尝试了 ykm29 的代码,但它无法正确填充子文件夹。这里的一些其他答案也使用单个路径部分来识别创建的 TreeNodes。如果不同目录中存在重复的文件夹名称,可能会导致我认为的问题。
因此,在我的代码中,我将“currentPath”值设置为文件夹的 TreeNodes 的键。下面代码中的“ExtendedFileInfo”扩展了“FileInfo”类,并为我自己的用例提供了一些附加属性。在调用此函数之前,创建根节点并将其分配给您的 TreeView。
private void MakeTreeViewFromPaths(TreeNode rootNode, List<ExtendedFileInfo> files, string rootNodeName = "C:\\", char separator = '\\')
{
foreach (var file in files)
{
TreeNode currentNode = rootNode;
string[] relPath = file.RelativePath.Split(separator);
string currentPath = rootNodeName;
//**Split operation always generates an empty entry so we use "-1" to avoid iterating through the last empty array item
for (int i = 0; i < relPath.Length - 1; i++)
{
currentPath += "\\" + relPath[i];
TreeNode[] tmp = currentNode.Nodes.Find(currentPath, true);
if (tmp.Length > 0)
{
currentNode = tmp[0];
continue;
}
//Create Folder Nodes
currentNode = currentNode.Nodes.Add(currentPath, relPath[i]);
}
//Create File Nodes
TreeNode newNode = new TreeNode(file.FileInfo.Name);
newNode.Tag = file;
//You can set different colors for different types of files with a custom method
HelperMethods.SetNodeColors(newNode, file.FileState);
currentNode.Nodes.Add(newNode);
}
}