none
如果数据库数据庞大,如何在WINFORM控件中提高treeview控件节点的展开效率?请高手解答,此帖发过一次了,几天了,急死了 RRS feed

  • 问题

  • using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;

    namespace WindowsFormsApplication17
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                TreeView tv = new TreeView();
                tv.AfterSelect += new TreeViewEventHandler(tv_AfterSelect);
                tv.Dock = DockStyle.Fill;
                this.BuildTree(tv.Nodes, 0);
                this.Controls.Add(tv);
            }

            private void tv_AfterSelect(object sender, TreeViewEventArgs e)
            {
                // 选择节点后,获取当前节点的信息
                // 你可以将下列信息赋给你对应的控件
                DataRow row = (DataRow)e.Node.Tag;

                Int32 FInterID = (Int32)row["FInterID"];
                Int32 ParentId = (Int32)row["FParentID"];
                String FName = (String)row["FName"];
            }

            private DataTable fSampleDataSource;
            public DataTable SampleDataSource
            {
                get  //这一段是我连接本人数据的代码
                {
                    SqlConnection thisconnection = new SqlConnection("server=(local);database=GADMEIERP;Integrated Security=true;");
                    SqlCommand cmd = thisconnection.CreateCommand();
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = "select FInterID,FParentID,FName,FNumber from ICBOMGROUP";
                    SqlDataAdapter adapter = new SqlDataAdapter();
                    adapter.SelectCommand = cmd;
                    DataSet ds = new DataSet();
                    adapter.Fill(ds, "ICBOMGROUP");
                    this.fSampleDataSource = ds.Tables[0];
                    return fSampleDataSource;
                }
            }

            /// <summary>
            /// 创建目录和文件树
            /// </summary>
            /// <param name="fNodes"> </param>
            /// <param name="fPath"> </param>
            public void BuildTree(TreeNodeCollection fNodes, Int32 fParentId)
            {
                foreach (DataRow row
                    in this.SampleDataSource.Select(String.Format("FParentID = {0}", fParentId)))
                {
                    TreeNode node = new TreeNode();
                    node.Text = row["FName"].ToString();
                    node.Tag = row;
                    // 递归创建子节点
                    this.BuildTree(node.Nodes, (Int32)row["FInterID"]);
                    fNodes.Add(node);
                }
            }

            private void Form1_Load(object sender, EventArgs e)
            {

            }
        }
    }


    另外我将数据库中的表结构贴出来如下:
    表名:ICBOMGROUP

    FInterID(BOM内码)    FParentID(父BOM内码)  FName(名称)      FNumber(产品代码)
    1039                              0                            产品                        0
    2296                              0                            喷印机壳                  1
    6497                              0                            丝印彩盒                  2
    7035                              0                            外发加工                  3
    1041                              1039                      VGA电视盒              01
    1071                              1041                      TV3488B系列          01.01
    1140                              1071                      TV2188EBOM          01.01.01
    1144                              1140                      普通订单                01.01.01.01
    1146                              1144                      TV2188E 中文BOM  01.01.01.01.01
    1145                              1140                      特殊订单                01.01.01.02
    1129                              1039                      XGA电视盒              02
    1199                              1129                      TV5811T系列          02.02
    1212                              1199                      TV5811BOM            02.02.01
    2297                              2296                      机壳-上盖                1.01
    2308                              2297                      GM998                    1.01.01
    2312                              2308                      GM998上盖 灰色      1.01.01.01
    7039                              7035                      支架组件                  3.01
    7040                              7039                      PD1048                  3.01.01
    7172                              7040                      PD1048支架组件      3.01.01.01


    在C#FORM界面中,要求有一个treeview控件,根据表结构,生成根结点和子结点:
    比如说FParentID为0,为一阶,再根据父节点和子节点依次生成下面的结点,例:
    0(产品)
      01(VGA电视盒)
        01.01(TV3488B系列)
            01.01.01(TV2188E BOM)
                01.01.01.01(普通订单)
                01.01.01.02(特殊订单)
    省略了

    供码测试通过没问题,但是只基于数据量少的情况下,如果有成千上万的数据量,这样的节点,一次性点击,要全部计算一次,效率是不是太有问题了???
       如果一次单击一个根节点,而只出现这个根节点的下一个节点,只计算这一次,效率上是不是会有提高,听有人说这样不能用递归,先将所有的节点先加上去,再使用鼠标所单击的节点,去计算下一个节点,是否效率会高一点.?请版主帮忙.
    2009年9月28日 3:46

答案

  • 你好!

    数据多可以选择一次只加载一部分节点,在 AfterSelect 事件中动态加载选中节点的子节点。这样可以避免加载一些用户不根本不看的节点。

    0(产品) // 初始时只加载 0
      01(VGA电视盒) // 点击 0 时从数据库读取 0 的子节点数据并创建子 0 的子节点

    还一种方式是在 BeforeExpand 事件中做,这样做的好处是节点前会有一个+号更直观一些,如:

    0(产品) 
      加载标识节点

    创建节点 0 时自动在0 这个节点中添加一个子节点叫"加载标识节点" 
    在 BeforeExpand 事件中,判断第一个节点的名称是否叫"加载标识节点" ,如果是就从数据库读子节点数据并创建节点。




    知识改变命运,奋斗成就人生!
    2009年9月28日 4:43
    版主
  • 你好!
         建议不要一次性加载所有的节点数据,可以在BeforeExpend中只加载本节点的子节点。
         另外,如果节点数据过多,建议修改一下设计,过多的节点展开和折叠通常会令用户比较困惑!建议进行合理分类后,用多个TreeView来呈现!
    周雪峰
    2009年9月28日 5:35
    版主
  • 另外补充一点,在做一些控件 Update 操作时,请在开始前调用 BeginUpdate,结束后调用 EndUpdate,会提高一些 Render 效率。
    Mark Zhou
    2009年9月28日 6:27

全部回复

  • 你好!

    数据多可以选择一次只加载一部分节点,在 AfterSelect 事件中动态加载选中节点的子节点。这样可以避免加载一些用户不根本不看的节点。

    0(产品) // 初始时只加载 0
      01(VGA电视盒) // 点击 0 时从数据库读取 0 的子节点数据并创建子 0 的子节点

    还一种方式是在 BeforeExpand 事件中做,这样做的好处是节点前会有一个+号更直观一些,如:

    0(产品) 
      加载标识节点

    创建节点 0 时自动在0 这个节点中添加一个子节点叫"加载标识节点" 
    在 BeforeExpand 事件中,判断第一个节点的名称是否叫"加载标识节点" ,如果是就从数据库读子节点数据并创建节点。




    知识改变命运,奋斗成就人生!
    2009年9月28日 4:43
    版主
  • 你好!
         建议不要一次性加载所有的节点数据,可以在BeforeExpend中只加载本节点的子节点。
         另外,如果节点数据过多,建议修改一下设计,过多的节点展开和折叠通常会令用户比较困惑!建议进行合理分类后,用多个TreeView来呈现!
    周雪峰
    2009年9月28日 5:35
    版主
  • 另外补充一点,在做一些控件 Update 操作时,请在开始前调用 BeginUpdate,结束后调用 EndUpdate,会提高一些 Render 效率。
    Mark Zhou
    2009年9月28日 6:27
  • 请XXY版主赐教,beforeexpand事件?偶不太明白,学习

    2009年9月28日 9:13
  • 节点展开多没关系,在金碟K3的系统的BOM展阶也是这样子的,主管要求做成那个效果,偶只能照做咯,请周版主赐教,代码如何修改啊?头疼了几天了
    2009年9月28日 9:15
  • BeforeExpand 是 TreeView 的一个事件,节点展开之前会调用这个事件。
    知识改变命运,奋斗成就人生!
    2009年9月28日 9:21
    版主
  • 能否请版主再次修改一下代码..?测试了几天还是不知道咋整...
    2009年9月29日 1:28