加速将字符串列表加载到 Treeview 中

5

我是Stackflow和C#的新手!

下面的代码可以将字符串列表加载到treeview控件中,它的工作效果很好。唯一的问题是速度。当列表很大时,加载需要时间,这并不是问题,但它会锁定UI一段时间。

例如,像这样的字符串列表(但要大得多):

c:\drivers\test1.txt
c:\drivers\test2.txt
c:\drivers\folder\test1.txt
c:\brother\tester\text1.zip
c:\brother\another\text2.zip
c:\data\company1\accounts.rar
c:\data\company2\accounts.rar

treeview使用反斜杠标记分割字符串,并将它们整齐地放在资源管理器视图中 - 这很好!

tvRestore是示例中的Treeview控件。

foreach (string path in lstKeys)
        {

            lastNode = null;
            subPathAgg = string.Empty;
            foreach (string subPath in path.Split(new string[] { "\\" }, StringSplitOptions.None))
            {
                foreach (string item in subPath.Split(new string[] { "\\" }, StringSplitOptions.None))
                {
                    if (item == "" || item == null)
                    {
                        continue;
                    }
                    subPathAgg += item + "\\";

                    TreeNode[] n = tvRestore.Nodes.Find(subPathAgg, true);

                    if (n.Length > 0)
                    {
                        lastNode = n[0];

                        continue;
                    }
                    else
                    {
                        // lastNode = null;
                    }

                    TreeNode[] nodes = tvRestore.Nodes.Find(subPathAgg, true);
                    if (nodes.Length == 0)
                        if (lastNode == null)
                            lastNode = tvRestore.Nodes.Add(subPathAgg, item);
                        else
                            lastNode = lastNode.Nodes.Add(subPathAgg, item);
                    else
                        lastNode = nodes[0];
                }
            }
        }

唯一的问题就是速度。我尝试使用线程,但代码会因为控件在不同线程上而出现异常。我相信我必须调用Nodes.Add方法,但我不知道如何做到这一点。

理想情况下,代码将在应用程序启动时开始填充树形视图,虽然我不希望应用程序因较大列表而锁定30-40秒或更长时间。

如何加快这个过程的最佳方法是什么?


2
尝试在添加节点之前使用 treeView1.BeginUpdate(); 关闭绘图,然后使用 EndUpdate(); 再次打开。 - LarsTech
1个回答

5

您可以采取一些措施,包括在后台运行此操作 - 我喜欢使用Task.Run()实现。

private void Form1_Load(object sender, EventArgs e)
{
    // Show the user something
    treeView1.Nodes.Add("Loading...");
    // Run the tree load in the background
    Task.Run(() => LoadTree());
}

然后您的任务可以构建一个包含所有新节点的TreeNode,并调用TreeView将新节点作为范围添加,同时使用BeginUpdate...EndUpdate以防止在加载所有节点之前进行视觉更新。

private void LoadTree()
{
    // Get a list of everything under the users' temp folder as an example
    string[] fileList;
    DirectoryInfo df = new DirectoryInfo(Path.GetTempPath());
    fileList = df.GetFiles("*.*",SearchOption.AllDirectories).Select<FileInfo, string>((f) => f.FullName).ToArray();

    // Parse the file list into a TreeNode collection
    TreeNode node = GetNodes(new TreeNode(), fileList);

    // Copy the new nodes to an array
    int nodeCount = node.Nodes.Count;
    TreeNode[] nodes = new TreeNode[nodeCount];
    node.Nodes.CopyTo(nodes, 0);

    // Invoke the treeview to add the nodes
    treeView1.Invoke((Action)delegate ()
    {
        treeView1.BeginUpdate(); // No visual updates until we say 
        treeView1.Nodes.Clear(); // Remove existing nodes
        treeView1.Nodes.AddRange(nodes); // Add the new nodes
        treeView1.EndUpdate(); // Allow the treeview to update visually
    });
}

这是我构建TreeNode列表的方法。
private TreeNode GetNodes(TreeNode parent, string[] fileList)
{
    // build a TreeNode collection from the file list
    foreach (string strPath in fileList)
    {
        // Every time we parse a new file path, we start at the top level again
        TreeNode thisParent = parent;

        // split the file path into pieces at every backslash
        foreach (string pathPart in strPath.Split('\\'))
        {
            // check if we already have a node for this
            TreeNode[] tn = thisParent.Nodes.Find(pathPart, false);

            if (tn.Length == 0)
            {
                // no node found, so add one
                thisParent = thisParent.Nodes.Add(pathPart,pathPart);
            }
            else
            {
                // we already have this node, so use it as the parent of the next part of the path
                thisParent = tn[0];
            }
        }

    }
    return parent;
}

在我的电脑上,用这种方式加载56,000个节点到树形视图大约需要1.5秒钟,并且不会阻塞用户界面。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接