0

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

数据库表如下所示:

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

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

谢谢您的帮助。

4

2 回答 2

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

此代码也适用于可变树深度 - 只有在当前级别找到节点时才会更深。顺便说一句,如果数据表很大,那么考虑对子节点进行延迟加载。在这种情况下,您也可以使用上述方法,但无需递归调用。

于 2012-11-11T22:21:15.967 回答
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 级中的每个节点都会有完全相同的子节点,这是预期的吗?

于 2012-11-11T22:06:47.767 回答