0

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

これらの 5 つのネストされたループの使用を避けるためのより良いアプローチがあるかどうか疑問に思っていました。オブジェクト指向のアプローチはありますか?

助けてくれてありがとう。

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

それでもかなり「ハック」に見えますが、間違いなくはるかにクリーンで、保守が簡単で、よりスケーラブルです。データベースの最大深度を照会することもでき、_maxDepthパラメーターをハードコーディングする代わりにプログラムで設定することもできます。

私が混乱していることの1つは、提示したコードがサブツリー内のすべてのノードに同じ子を追加することです。例:レベル2のすべてのノードには、まったく同じ子がありますが、それは予想されますか?

于 2012-11-11T22:06:47.767 に答える