C# 使用WinForms TreeView的递归目录列表?

C# 使用WinForms TreeView的递归目录列表?,c#,treeview,filesystems,populate,C#,Treeview,Filesystems,Populate,我想做一个树状视图,显示系统上的所有文件夹,只显示音乐文件,如.mp3.aiff.wav等 我记得我读过一篇文章,说我需要使用递归函数或类似的东西。递归地搜索所有驱动器中的特定文件不会很好。对于今天的大型驱动器,这样做大约需要一分钟的时间 Windows资源管理器使用的一个标准技巧是只列出顶级目录和文件。它将虚拟节点放在目录节点中。当用户打开节点(BeforeExpand事件)时,它只搜索该目录,并用在该目录中找到的目录和文件替换虚拟节点。再次在目录中放置虚拟节点。等等 通过添加一个空的子目录,

我想做一个树状视图,显示系统上的所有文件夹,只显示音乐文件,如.mp3.aiff.wav等


我记得我读过一篇文章,说我需要使用递归函数或类似的东西。

递归地搜索所有驱动器中的特定文件不会很好。对于今天的大型驱动器,这样做大约需要一分钟的时间

Windows资源管理器使用的一个标准技巧是只列出顶级目录和文件。它将虚拟节点放在目录节点中。当用户打开节点(BeforeExpand事件)时,它只搜索该目录,并用在该目录中找到的目录和文件替换虚拟节点。再次在目录中放置虚拟节点。等等

通过添加一个空的子目录,可以看到这一点。目录节点将以+字形显示。打开时,资源管理器发现没有要列出的目录或文件,并删除虚拟节点。+字形消失

这非常快,列出单个目录的内容只需不到一秒钟的时间。然而,在您的案例中使用这种方法存在一个问题。目录中包含合适音乐文件的几率很小。当用户发现在一组子目录中导航不会产生任何结果时,会经常感到沮丧


这就是为什么Windows有一个专用的位置来存储特定的媒体文件。我的音乐在这种情况下。使用Environment.GetFolderPath(Environment.SpecialFolder.MyMusic)查找它。迭代不会花费很长时间。

通常大多数计算机都有数千个文件夹和数十万个文件,因此以递归方式在树状视图中显示所有文件夹和文件会非常慢,并且会消耗大量内存,请在中查看我的答案,并在可以获得非常有用的GUI时引用我的答案并进行一些修改:

// Handle the BeforeExpand event
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
   if (e.Node.Tag != null) {
       AddDirectoriesAndMusicFiles(e.Node, (string)e.Node.Tag);
   }
}

private void AddDirectoriesAndMusicFiles(TreeNode node, string path)
{
    node.Nodes.Clear(); // clear dummy node if exists

    try {
        DirectoryInfo currentDir = new DirectoryInfo(path);
        DirectoryInfo[] subdirs = currentDir.GetDirectories();

        foreach (DirectoryInfo subdir in subdirs) {
            TreeNode child = new TreeNode(subdir.Name);
            child.Tag = subdir.FullName; // save full path in tag
            // TODO: Use some image for the node to show its a music file

            child.Nodes.Add(new TreeNode()); // add dummy node to allow expansion
            node.Nodes.Add(child);
        }

        List<FileInfo> files = new List<FileInfo>();
        files.AddRange(currentDir.GetFiles("*.mp3"));
        files.AddRange(currentDir.GetFiles("*.aiff"));
        files.AddRange(currentDir.GetFiles("*.wav")); // etc

        foreach (FileInfo file in files) {
            TreeNode child = new TreeNode(file.Name);
            // TODO: Use some image for the node to show its a music file

            child.Tag = file; // save full path for later use
            node.Nodes.Add(child);
        }

    } catch { // try to handle use each exception separately
    } finally {
        node.Tag = null; // clear tag
    }
}

private void MainForm_Load(object sender, EventArgs e)
{
    foreach (DriveInfo d in DriveInfo.GetDrives()) {
        TreeNode root = new TreeNode(d.Name);
        root.Tag = d.Name; // for later reference
        // TODO: Use Drive image for node

        root.Nodes.Add(new TreeNode()); // add dummy node to allow expansion
        treeView1.Nodes.Add(root);
    }
}
//处理BeforeExpand事件
私有void treeView1_在展开之前(对象发送方,TreeViewCancelEventArgs e)
{
如果(e.Node.Tag!=null){
addDirectories和音乐文件(e.Node,(string)e.Node.Tag);
}
}
私有void addDirectories和MusicFile(TreeNode节点,字符串路径)
{
node.Nodes.Clear();//清除虚拟节点(如果存在)
试一试{
DirectoryInfo currentDir=新的DirectoryInfo(路径);
DirectoryInfo[]subdirs=currentDir.GetDirectories();
foreach(目录信息子目录中的目录信息子目录){
TreeNode子节点=新的TreeNode(子节点名称);
child.Tag=subdir.FullName;//在标记中保存完整路径
//TODO:为节点使用一些图像以显示其音乐文件
child.Nodes.Add(new TreeNode());//添加虚拟节点以允许扩展
node.Nodes.Add(子节点);
}
列表文件=新列表();
files.AddRange(currentDir.GetFiles(“*.mp3”);
files.AddRange(currentDir.GetFiles(“*.aiff”);
files.AddRange(currentDir.GetFiles(“*.wav”);//等
foreach(文件中的文件信息文件){
TreeNode子节点=新的TreeNode(file.Name);
//TODO:为节点使用一些图像以显示其音乐文件
child.Tag=file;//保存完整路径供以后使用
node.Nodes.Add(子节点);
}
}catch{//尝试分别处理和使用每个异常
}最后{
node.Tag=null;//清除标记
}
}
私有void主窗体加载(对象发送方、事件参数e)
{
foreach(DriveInfo.GetDrives()中的DriveInfo d){
TreeNode root=新的TreeNode(d.Name);
root.Tag=d.Name;//供以后参考
//TODO:使用节点的驱动器映像
root.Nodes.Add(new TreeNode());//添加虚拟节点以允许扩展
treeView1.Nodes.Add(根);
}
}

为什么在问题上加上“active directory”标签?这与广告无关,顺便问一下,这是哪种技术?Windows窗体、WPF、ASP.NET、Silverlight?很好的代码伙伴!羞耻不是一个正确的答案——我认为应该是这样,因为它似乎很好地解决了这个问题。谢谢,我在数据库节点表填充中使用了类似的代码。所以刷新很简单,只需设置node.Tag=null。为了避免不必要的检索,使用虚拟节点真是个好主意。跳出框框的思维方式。太棒了!这真方便!