views:

651

answers:

3

I have some serious problems with populating a treeview recursively and I'll apreciate any help.

I have this DataTable:

ItemID ItemDesc  Project  Room  Closet  

Item1  Item1Desc Project1 RoomE Closet-7  
Item2  Item2Desc Project1 RoomW Closet8  
Item3  Item3Desc Project1 RoomW Closet8  
Item4  Item4Desc Project1 RoomN Closet2  
Item5  Item5Desc Project1 RoomN Closet9  
Item6  Item6Desc Project2 RoomN Closet2  
Item7  Item7Desc Project2 RoomW Closet9  

I want to create a TreeView like this:

  • Project1
    • RoomE
      • Closet7
        • Item1Desc
    • RoomW
      • Closet8
        • Item2Desc
        • Item3Desc
    • RoomN
      • Closet2
        • Item4Desc
      • Closet9
        • Item5Desc
  • Project2
    • RoomN
      • Closet2
        • Item6Desc
    • RoomW
      • Closet2
        • Item7Desc

The way I'm trying to databind the treeview is using

private List<treeDataItem> treeData = new List<treeDataItem>();  
mytreeView.DataFieldID = "ID";  
mytreeView.DataFieldParentID = "ParentID";  
mytreeView.DataTextField = "Text";  
mytreeView.DataValueField = "Value";  
mytreeView.DataSource = treeData;  
mytreeView.DataBind();

I'm trying to loop thru the DataTable so I can populate treeData but i can't enter the ParentIDs correctly.

Also, to make things complicated the number of fields in the DataTable are variable.
Which means that I can have more fields that identify an item like a "Closet Drawer" and then maybe a "Closet Drawer Section", etc.

So the DataTable can one time be like:

ItemID     ItemDescription     Project     Room     Closet     Closet Drawer  

And another time like:

ItemID     ItemDescription     Project     Room     Closet     Closet Drawer     Closet Drawer Section

based on user selection.

Here's the treeDataItem class:

internal class treeDataItem
{
    public string Text { get; set; }
    public int ID { get; set; }
    public int ParentID { get; set; }
    public Guid Value { get; set; }

    public treeDataItem(int id, int parentId, string text, string value)
    {
        ID = id;
        ParentID = parentId;
        Text = text;
        Value = value;
    }
}
A: 

I have no expertise in C# but I'd approach a problem like that in two stages:

  1. Parse the input into something usable.
  2. Then bind the treeview to it.

Your input data is fairly complex so a custom parser to handle all the special situations is well justified.

Sarge
A: 
            string[] data = new string[] {
            "Item1 Item1Desc Project1 RoomE Closet-7",
            "Item2 Item2Desc Project1 RoomW Closet8",
            "Item3 Item3Desc Project1 RoomW Closet8",
            "Item4 Item4Desc Project1 RoomN Closet2",
            "Item5 Item5Desc Project1 RoomN Closet9",
            "Item6 Item6Desc Project2 RoomN Closet2",
            "Item7 Item7Desc Project2 RoomW Closet9" };

        foreach (string row in data)
        {
            string[] columns = row.Split(' ');

            TreeNodeCollection treeNodes=treeView1.Nodes;

            for (int col = 2; col < columns.Length; col++)
            {
                string column = columns[col];
                if (!treeNodes.ContainsKey(column))
                {
                    treeNodes.Add(column, column);
                }
                TreeNode tn = treeNodes[column];
                treeNodes = tn.Nodes;
            }
            treeNodes.Add(string.Format("{0} - {1}", columns[0], columns[1]));
        }
Guge
+1  A: 

I'm not familiar with the ASP.NET treeview control, so here's a generic solution.

DateTable row

class Foo
{
    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }
}

Tree node

class Node
{
    private readonly string name;
    private readonly Node[] children;

    public Node(string name, Node[] children)
    {
        this.name = name;
        this.children = children;
    }
}

Recursive algorithm to group rows into nodes

static IEnumerable<Node> Traverse<T, U>(
    IEnumerable<T> items,
    Func<T, U>[] keySelectors,
    int selectorIndex)
{
    if (selectorIndex < keySelectors.Length)
    {
        foreach (var g in items.GroupBy(keySelectors[selectorIndex]))
        {
            yield return new Node(g.Key.ToString(),
                Traverse(g, keySelectors, selectorIndex + 1).ToArray());
        }
    }
}

Test

var items = new[]
               {
                   new Foo { A = "A1", B = "B1", C = "C1" },
                   new Foo { A = "A1", B = "B1", C = "C2" },
                   new Foo { A = "A1", B = "B2", C = "C1" },
                   new Foo { A = "A1", B = "B2", C = "C2" },
                   new Foo { A = "A2", B = "B1", C = "C1" },
                   new Foo { A = "A2", B = "B1", C = "C2" },
                   new Foo { A = "A2", B = "B2", C = "C1" },
                   new Foo { A = "A2", B = "B2", C = "C2" },
               };

var nodes = Traverse(items, new Func<Foo, string>[]
                            {
                                f => f.A,
                                f => f.B,
                                f => f.C
                            }, 0).ToArray();

Output

  • A1
    • B1
      • C1
      • C2
    • B2
      • C1
      • C2
  • A2
    • B1
      • C1
      • C2
    • B2
      • C1
      • C2
dtb