在最小化到下一级文件夹时,TreeView扩展仍然需要一段时间

时间:2016-08-07 22:44:57

标签: c# winforms treeview

我有以下代码,当用户展开treenode时,使用系统中的文件夹构建TreeView。

protected override void OnBeforeExpand(TreeViewCancelEventArgs e)
{

    if (!_expandedCache.Contains((string)e.Node.Tag))
    {
        BeginUpdate();
        ShellFileGetInfo.FolderIcons fi;
        IEnumerable<string> dirs;
        string path;
        string currentPath;

        _expandedCache.Add((string)e.Node.Tag);

        TreeNode n;
        foreach (TreeNode node in e.Node.Nodes)
        {
            try
            {
                path = (string)node.Tag;
                dirs = Directory.EnumerateDirectories(path).OrderBy(d => d).Select(d => d.Split(Path.DirectorySeparatorChar).Last());
                foreach (string dir in dirs)
                {
                    currentPath = Path.Combine(path, dir);
                    if (File.Exists(Path.Combine(currentPath, "desktop.ini")) == true)
                    {
                        fi = ShellFileGetInfo.GetFolderIcon(currentPath, false);
                        ImageList.Images.Add(fi.closed);
                        ImageList.Images.Add(fi.open);
                        n = node.Nodes.Add(currentPath, dir, ImageList.Images.Count - 2, ImageList.Images.Count - 1);
                        n.Tag = currentPath;
                    }
                    else
                    {
                        n = node.Nodes.Add(currentPath, dir, 0, 1);
                        n.Tag = currentPath;
                    }
                }
            }
            catch (UnauthorizedAccessException)
            {

            }
        }
        EndUpdate();
    }
    base.OnBeforeExpand(e);
}

设置初始TreeView的代码是通过我的SetRoot方法完成的,如下所示:

public void SetRoot(string path)
{
    _expandedCache = new List<string>();
    Tag = path;
    BeginUpdate();

    ShellFileGetInfo.FolderIcons fi;
    IEnumerable<string> dirs;
    string currentPath;

    TreeNode n;

    dirs = Directory.EnumerateDirectories(path).OrderBy(d => d).Select(d => d.Split(Path.DirectorySeparatorChar).Last());
    foreach (string dir in dirs)
    {
        currentPath = Path.Combine(path, dir);
        if (File.Exists(Path.Combine(currentPath, "desktop.ini")) == true)
        {
            fi = ShellFileGetInfo.GetFolderIcon(currentPath, false);
            ImageList.Images.Add(fi.closed);
            ImageList.Images.Add(fi.open);

            n = Nodes.Add(currentPath, dir, ImageList.Images.Count - 2, ImageList.Images.Count - 1);
            n.Tag = currentPath;
        }
        else
        {
            n = Nodes.Add(currentPath, dir, 0, 1);
            n.Tag = currentPath;
        }
    }

    foreach (TreeNode node in Nodes)
    {
        path = (string)node.Tag;
        try
        {
            dirs = Directory.EnumerateDirectories(path).OrderBy(d => d).Select(d => d.Split(Path.DirectorySeparatorChar).Last());
            foreach (string dir in dirs)
            {
                currentPath = Path.Combine(path, dir);
                if (File.Exists(Path.Combine(currentPath, "desktop.ini")) == true)
                {
                    fi = ShellFileGetInfo.GetFolderIcon(currentPath, false);
                    ImageList.Images.Add(fi.closed);
                    ImageList.Images.Add(fi.open);
                    n = node.Nodes.Add(currentPath, dir, ImageList.Images.Count - 2, ImageList.Images.Count - 1);
                    n.Tag = currentPath;
                }
                else
                {
                    n = node.Nodes.Add(currentPath, dir, 0, 1);
                    n.Tag = currentPath;
                }
            }
        }
        catch (UnauthorizedAccessException)
        {

        }
    }
    EndUpdate();
}

为了让节点显示它是可扩展的,我必须在树视图中加载至少1个额外的深度。所以对于“c:\ windows \”我需要加载system32等。当用户扩展“Windows”时,在OnBeforeExpand中,我需要填充所有子文件夹的子文件夹,使它们看起来是可扩展的。为了防止在重新扩展时加载树内容(当用户折叠Windows并重新扩展Windows时),我会缓存已经在某些时候展开的TreeNodes列表。 (这显然会产生未来的影响,例如,如果用户在Windows资源管理器中添加了一个文件夹,它没有显示,但这是一个不同的故事)。

在获取特殊图标时,我发现最简单的方法是将SHGetFileInfo p / invoke仅用于包含名为“desktop.ini”的文件的文件夹。

我的问题是,无论我做什么,我都无法在任何合理的标准内执行此TreeView。扩展“Windows”树需要9秒,而扩展只有4个文件夹的“inetpub”需要4秒。我认为减速是由于UnauthorizedAccessException,我无法在不遇到这些情况的情况下看到枚举目录。

TreeView

正如您所见,视觉上它正在按预期运行,但扩展一些文件夹需要很长时间(比Windows资源管理器长得多)。您看到的初始视图需要大约200毫秒才能加载(仍然很慢,但可以忍受)

TreeView Windows

充其量只花了8秒,最糟糕的是14次,超过10次测试填充 - Windows资源管理器是即时的

我可以做些什么来进一步提高性能? ...这样可以使用,而不是比Windows资源管理器的版本差!

1 个答案:

答案 0 :(得分:1)

尝试在树中动态添加的数据存在于文件系统中。 在文件模式下访问数据有时可能会降低速度,具体取决于操作系统和处理器的活动。 如果您可以在某个数据库中移动数据,并通过从数据库中提取数据在树中添加节点,它将加速。

您可以在SQLSERVER中以varbinary数据类型在数据库中添加图像。

即使Windows资源管理器也使用相同的技术。