TreeView expand still taking a while when minimizi

2019-07-24 15:16发布

问题:

I have the following code which builds a TreeView using the folders from the system when the user expands a treenode.

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

The code to setup the initial TreeView is done via my SetRoot method which is as follows :

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();
}

In order for the node to show it is expandable, I must load into the treeview at a minimum 1 additional level deep. So for "c:\windows\" i need to load system32, etc. When the user expands "Windows", in the OnBeforeExpand, i need to populate all the subfolders' subfolders to make those appear expandable. To prevent loading the tree contents on re-expansion (when the user collapses Windows and re-expands Windows), I cache a list of the TreeNodes which have already been expanded at some point. (this obviously has future repercussions like if the user adds a folder in windows explorer, it not showing, but that is a different story).

When it comes to getting special icons, I found the cheapest way to minimize on this is to only use the SHGetFileInfo p/invoke for folders that contain a file named 'desktop.ini'.

My problem is, no matter what I do, I can not make this TreeView perform within any reasonable standard. It takes 9 seconds to expand the "Windows" tree, and 4 seconds to expand "inetpub" which only has 4 folders. I believe the slow-down is due to UnauthorizedAccessException which there is no way that I can see to enumerate directories without encountering that.

as you can see, visually it is operating as expected, but expanding some folders, takes a really long time (much longer than windows explorer). The initial view as you see took about 200ms to load (still slow, but bearable)

took 8 seconds at best, 14 seconds at worst over 10 tests to populate - windows explorer is instant

What can I do to improve the performance of this further ? ... so that this is viable to use, not worse than Windows Explorer's version !

回答1:

Data which are trying to add dynamically in tree exist in File System. Accessing data in file mode can slow down at times depending on OS and activity of processors. If you can move your data in some database, and add nodes in tree by pulling data from Database, it will speed up.

You can add images in database in varbinary datatype in SQLSERVER.

Even Windows Explorer uses same kind of techniques.