避免为每个循环嵌套以在TreeView中加载项目

时间:2012-11-11 21:48:18

标签: c# .net treeview

我有一个从数据库表加载的数据表,其中包含要加载到treeView中的元素。

数据库表如下所示:

+--------+---------+-------------------------------+
|liv     | cod     | des                           |
|--------+---------+-------------------------------+
| 1      | AAA     |    PANE E SOSTITUTIVI     |
| 2      | AAAA    |GRISSINI - CRACKERS E SIMIL    |
| 3      | AAAA    |    MAIS                   |
| 4      | AAAA B  |    BIANCO                 |
| 4      | AAAA I  |    INTEGRALE              |
| 3      | AAAAA   |    AVENA                  |
| 4      | AAAAAB  |    BIANCO                 |
| 4      | AAAAAI  |    INTEGRALE              |
| 3      | AAAAB   |    ALTRO                  |
| 4      | AAAABB  |    BIANCO                 |
| 4      | AAAABI  |    INTEGRALE              |
| 3      | AAAAF   |    FARRO                  |
| 4      | AAAAFB  |    BIANCO                 |
| 4      | AAAAFI  |    INTEGRALE              |
| 3      | AAAAK   |    KAMUT                  |
| 4      | AAAAKB  |    BIANCO                 |
| 4      | AAAAKI  |    INTEGRALE              |
| 3      | AAAAR   |    FRUMENTO               |
| 4      | AAAARB  |    BIANCO                 |
| 4      | AAAARI  |    INTEGRALE              |
| 3      | AAAAS   |    RISO                   |
| 4      | AAAASB  |    BIANCO                 |
| 4      | AAAASI  |    INTEGRALE              |
| 2      | AAAC    |    ESTRUSI                |
| 3      | AAACA   |    MAIS               |
+--------+---------+-------------------------------+

由于树的最大级别(liv)是5,这里是我正在使用的函数将数据表加载到TreeView中:

   public void loadFromDataTable(DataTable table, TreeView tree) {

        DataView view1 = new DataView(table);
        view1.RowFilter = "liv = 1";

            foreach (DataRowView dr in view1) {
                TreeNode root = new TreeNode(dr["des"].ToString());
                DataView view2 = new DataView(table);
                view2.RowFilter = "liv = 2 AND cod LIKE '" + dr["cod"].ToString().Trim() + "%'";

                foreach (DataRowView dr2 in view2) {
                    TreeNode root2 = new TreeNode(dr2["des"].ToString());

                    DataView view3 = new DataView(table);
                    view3.RowFilter = "liv = 3 AND cod LIKE '" + dr2["cod"].ToString().Trim() + "%'";

                    foreach (DataRowView dr3 in view3) {
                        TreeNode root3 = new TreeNode(dr3["des"].ToString());

                        DataView view4 = new DataView(table);
                        view4.RowFilter = "liv = 4 AND cod LIKE '" + dr3["cod"].ToString().Trim() + "%'";

                        foreach (DataRowView dr4 in view4) {
                            TreeNode root4 = new TreeNode(dr4["des"].ToString());

                            DataView view5 = new DataView(table);
                            view5.RowFilter = "liv = 5 AND cod LIKE '" + dr4["cod"].ToString().Trim() + "%'";

                            foreach (DataRowView dr5 in view5) {
                                TreeNode root5 = new TreeNode(dr5["des"].ToString());

                                root4.Nodes.Add(root5);
                            }

                            root3.Nodes.Add(root4);
                        }

                        root2.Nodes.Add(root3);
                    }

                    root.Nodes.Add(root2);
                }
                tree.Nodes.Add(root);
            }

我想知道是否有更好的方法来避免使用这五个嵌套循环。任何面向对象的方法?

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

您可以使用递归来添加节点:

private TreeNode[] GetNodes(DataTable table, int level = 1, string code = "")
{
    return table.AsEnumerable()
                .Where(row => row.Field<int>("liv") == level
                              && row.Field<string>("cod").StartsWith(code))
                .Select(row =>
                {
                    var node = new TreeNode(row.Field<string>("des"));
                    node.Nodes.AddRange(GetNodes(table, level + 1, row.Field<string>("cod")));
                    return node;
                })
                .ToArray();
}

使用非常简单:

treeView.Nodes.AddRange(GetNodes(table));

此代码也适用于可变树深度 - 只有在当前级别找到节点时才会更深入。 BTW如果datatable很大,那么考虑延迟加载子节点。在这种情况下,您也可以使用上面的方法,但不需要递归调用。

答案 1 :(得分:1)

这样的东西应该有用(我没有编译/运行代码,但它应该给你一个好主意):

private int _maxDepth = 5;
public void loadFromDataTable(DataTable table, TreeView tree)
{
    DataView view1 = new DataView(table);
    view1.RowFilter = "liv = 1";

    foreach (DataRowView dr in view1) 
    {
        TreeNode node = new TreeNode(dr["des"].ToString());
        buildTree(table, node, 2);
        tree.Nodes.Add(node);
    }
}

public void buildTree(DataTable table, TreeNode parent, int level)
{
    if(level <= _maxDepth)
    {
        DataView view = new DataView(table);
        view.RowFilter = "liv = " + level + " AND cod LIKE '" + dr["cod"].ToString().Trim() + "%'";

        foreach (DataRowView dr in view) {
            TreeNode node = new TreeNode(dr["des"].ToString());
            buildTree(table, node, level+1);
            parent.Nodes.Add(node);
        }
    }
}

它仍然看起来非常“hackish”,但它肯定更清洁,更易于维护和更具可扩展性。您还可以查询数据库的最大深度,并且可以以编程方式设置_maxDepth参数,而不必对其进行硬编码。

我对此感到困惑的一件事:您呈现的代码为子树中的每个节点附加相同的子代。例如:级别2中的每个节点都具有完全相同的子节点,是预期的吗?