C# 如何以最快的方式在树视图中添加节点?

C# 如何以最快的方式在树视图中添加节点?,c#,winforms,.net-2.0,C#,Winforms,.net 2.0,你好 我想听听你对这件事的建议 我正在办公室制作一个小工具,将“产品层次结构数据”显示到树状视图中。我们的应用程序只能以表格的方式显示,如果层次结构中存在任何不正确的数据,则很难进行跟踪 我能够做出一些逻辑并以正确的层次结构显示数据 但我这里的主要问题是我要处理100K-200K+记录,创建/分配每个节点并将其添加到树中肯定需要时间。根据我的测试,平均每分钟可以创建8000个节点。我还注意到,随着应用程序的运行,其内存使用逐渐增加 我将包括数据结构的屏幕截图以及应用程序的外观,以让您了解:

你好

我想听听你对这件事的建议

我正在办公室制作一个小工具,将“产品层次结构数据”显示到树状视图中。我们的应用程序只能以表格的方式显示,如果层次结构中存在任何不正确的数据,则很难进行跟踪

我能够做出一些逻辑并以正确的层次结构显示数据

但我这里的主要问题是我要处理100K-200K+记录,创建/分配每个节点并将其添加到树中肯定需要时间。根据我的测试,平均每分钟可以创建8000个节点。我还注意到,随着应用程序的运行,其内存使用逐渐增加

我将包括数据结构的屏幕截图以及应用程序的外观,以让您了解:

请考虑下面的代码,我很高兴知道你的想法,如何优化这一点。我知道这里有很多地方需要改进

很抱歉发了这么长的帖子

顺便说一下,我正在使用C#和.net2.0

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Data;
using System.IO;
using System.Threading;

namespace WinformAppTest
{
    public partial class MainForm : Form
    {
        private DataSet _ds = new DataSet();

        public MainForm()
        {
            InitializeComponent();
        }

        void MainFormLoad(object sender, EventArgs e)
        {
            PopulateDataSet();

            lblTotalRows.Text = _ds.Tables[0].Rows.Count.ToString();
        }

        void PopulateDataSet()
        {
            string query = @"select * from " + "test.csv";
            try
            {
                OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\\;Extended Properties=\"Text;HDR=Yes;FMT=Delimited\"");
                OleDbDataAdapter da = new OleDbDataAdapter();

                OleDbCommand cmd = new OleDbCommand(query, conn);
                conn.Open();
                da.SelectCommand = cmd;
                _ds.Clear();
                da.Fill(_ds, "CSV");

                conn.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.GetBaseException().ToString());
            }
        }

        void BtnRunClick(object sender, EventArgs e)
        {
            Thread newThread1 = new Thread(MainForm.DoWork);
            newThread1.Start(this);
        }

        public static void DoWork(object data)
        {
            MainForm form = (MainForm)data;
            int counter = 0;
            TreeNode[] nd;

            foreach(DataRow row in ((MainForm)data)._ds.Tables[0].Rows)
            {
                TreeNode node = new TreeNode();
                if(row["Level Number"].ToString() == "1")
                {           
                    node.Name = row["ECC Hierarchy Code"].ToString();
                    node.Text = row["ECC Hierarchy Code"].ToString() + ", " + row["Name"].ToString();

                    form.Invoke((MethodInvoker)delegate { ((MainForm)data).treeView1.Nodes.Add(node); });       
                }
                else
                {                   
                    nd = ((MainForm)data).treeView1.Nodes.Find(row["Parent Code"].ToString(), true);
                    node.Name = (string)row["ECC Hierarchy Code"];
                    node.Text = row["ECC Hierarchy Code"].ToString() + ", " + row["Name"].ToString();

                    form.Invoke((MethodInvoker)delegate { nd[0].Nodes.Add(node); });
                }

                counter++;
                form.Invoke((MethodInvoker)delegate { ((MainForm)data).lblLoded.Text = counter.ToString(); });
            }       
        }
    }
}

处理大型数据集时,内置WinForms控件受到限制。据我回忆,内置的TreeView将尝试为每个节点分配自己的内存(这意味着您为每个100K+记录分配了一份数据副本,外加额外的元数据,即使大多数记录不会在给定会话中查看)

我使用开源的TreeView替代方案获得了很大的成功,该替代方案提供了虚拟节点(只有在它们变得可见时才进行渲染)

一些想法

  • 您使用线程获取数据,然后使用Invoke将每个数据项添加到树中。这非常缓慢。更好的方法是使用线程获取所需的所有数据,然后使用treeView1.nodes.AddRange()将所有节点一次添加到树中

  • 您可以通过重新设计应用程序进行更多优化,使其获取第一级节点的所有数据,然后在用户展开树节点时仅获取较低级别节点的数据


  • 关键在于以下几点:

  • 调用TreeView.BeginUpdate
  • 向树视图添加/删除多个节点
  • 调用TreeView.EndUpdate
  • 这将停止在添加/删除节点时发生的任何绘制。一旦调用EndUpdate,整个树视图只绘制一次


    收费的话,还有各种COTS解决方案可以很好地处理大型数据集…@pst:是的,例如Telerik非常好。但是如果一个人希望替换特定的控件而不是获得一个框架,开源替代方案就可以很好地工作。嘿,这是真的。(虽然不是所有的COTS都是一个完整的框架,我会对Telerik闭口不谈。它归结为需求和权衡;-)@pst:爱它,恨它。人们当然对Telerik充满热情…:-)可能取决于你希望它能为你做些什么,以及你使用的具体产品。你的第一个提示对我的情况有很大的影响。向treeview添加120万个节点是不可能的,一次添加一个节点。虽然这需要一些时间,而且应用程序现在分配700MB内存,但它确实会加载和显示。你可以看到n task mgr发现,节点的加载在内存分配方面要快得多。