1

I have this structure of List<Object>, to be specific it is a "CategoryItem" Object. Here's my declaration of "CategoryItem" Object.

public class CategoryItem
{
    public string Name { get; set; }
    public int CategoryID {get; set;}
    public int ParentID {get; set; }
    public List<CategoryItem> SubCategory {get; set;}
}

Here's my sample data structure:

[0] CategoryID: 249
Name: "WelcomeNC"
ParentID: 0
SubCategory: length=4
    [0] CategoryID: 250
        Name: "CNC"
        ParentID: 249
        SubCategory: length=0
    [1] CategoryID: 251
        Name: "Production"
        ParentID: 249
        SubCategory: length=0
    [2] CategoryID: 252
        Name: "Administrative"
        ParentID: 249
        SubCategory: length=1
            [0] CategoryID: 261
                Name: "NPower"
                ParentID: 252
                SubCategory: length=0
    [3] CategoryID: 253
        Name: "Help"
        ParentID: 249
        SubCategory: length=1
            [0] CategoryID: 254
                Name: "7"
                ParentID: 253
                SubCategory: length=1
                    [0] CategoryID: 255
                        Name: "CHLK"
                        ParentID: 254
                        SubCategory: length=0
[1] CategoryID: 111
Name: "First"
ParentID: 0
SubCategory: length=0

My problem is, how do I step in each and every 'CategoryItem' object of my declared:

List<CategoryItem> categoryItems = new List<CategoryItem>();

So that I can display it in an unordered list in html like this

  • WelcomeNC
    • CNC
    • Production
    • Administrative
      • NPower
    • Help
      • 7
        • CHLK
  • First

Is there a way to do this?

chlkdst
  • 175
  • 3
  • 13
  • Sorry I had a typographical error... I just fixed my 'CategoryItem' Object with member variable List – chlkdst Jun 04 '12 at 08:28
  • @L.B: Yes, but OP said that the tree represents data structure, not visualizes it (otherwise he already have a sort of recursive algorithm to build such a tree from the relational source). So I still thinks that tree and declaration has discrepancy. – abatishchev Jun 04 '12 at 08:33

5 Answers5

1

Maybe take a look at the TreeView control? http://msdn.microsoft.com/en-us/library/7a9swst5(v=vs.80).aspx

The ASP.NET TreeView control is designed to present users with data in a hierarchical structure. Users can open individual nodes that can in turn contain child nodes. The TreeView control is suitable for displaying XML data, but can be used for any data that can be represented in a hierarchy.

I think it will be what you want.

Otherwise, it's a matter of iterating through each item in your list and recursively processing each sub-item which may or may not have more sub-items. It's tricky, but only at first.

Rob P.
  • 14,921
  • 14
  • 73
  • 109
  • Will this allow me to use my current data structure of "CategoryItem" given above sir? What I want to do is to render objects into an ordinary
      and
    • HTML tags and my AJAX will do the rendering for tree... I'm following an MVC 3 pattern with Razor of ASP.NET sir
    – chlkdst Jun 04 '12 at 08:34
1

You need to create a recursive Method that "renders" a category item. This methods needs to be aware of the level or current depth in order render to correct indenting:

private void RenderCategory(HtmlTextWriter writer, CategoryItem item, int level)
{
  writer.Write("<li style='padding-left: {0}px'>{1}</li>", 
    level * 5,
    HttpUtility.HtmlEncode(item.Name));

  int nextLevel = ++level;
  foreach (CategoryItem child in item.SubCategories)
  { 
    RenderCategory(writer, child, nextLevel);
  }
}
Stefan
  • 14,530
  • 4
  • 55
  • 62
  • CategoryItem in the argument passed isn't a List object sir. How will I pass a single CategoryItem if I have this object "List categoryItems = new List();" ? – chlkdst Jun 04 '12 at 08:50
1

A simple not optimal but simple solution will be to just iterate the list and for each of the items you count how many times you call its parent id before it its 0. So then you know how many levels of identation your <li> must have.

Erre Efe
  • 15,387
  • 10
  • 45
  • 77
  • Would you mind giving a pseudocode for easy visualization of your thought sir? I really don't have any idea on how to step on each data on my object... How will I know I this object has 3 level deep of subcategory – chlkdst Jun 04 '12 at 08:38
1

If your CategoryItem doesn't contain a list of its children (like in the first version of the question), I would first of all build a Dictionary that foreach CategoryID gives you all the subcategory items, then recursively print all your items using this dictionary and starting with the items with parent "0". Assuming that Print is the instruction that print the data associated with your item, and that it takes as the only parameter the level of indentation, the code will look like this:

    public static void PrintItems(List<CategoryItem> items)
    {
        Dictionary<string, List<CategoryItem>> dictOfChildren = new Dictionary<string, List<CategoryItem>>();
        // loop through all the items grouping them according to their ParentID
        foreach (CategoryItem anItem in items)
        {
            List<CategoryItem> children;
            if (!dictOfChildren.TryGetValue(anItem.ParentID, out children))
            {
                children = new List<CategoryItem>();
                dictOfChildren[anItem.ParentID] = children;
            }
            children.Add(anItem);
        }
        // recursively print all the items starting from the ones with ParentID = 0
        // the dictionary is passed to the method in order to be able to find the children of each item
        PrintItems(dictOfChildren["0"], dictOfChildren, 0);
    }

    private static void PrintItems(List<CategoryItem> list, Dictionary<string, List<CategoryItem>> dictOfChildren, int levelOfIndentation)
    {
        foreach (CategoryItem anItem in list)
        {
            // first print the current item
            anItem.Print(levelOfIndentation);
            // then recursively print all its children
            List<CategoryItem> children;
            if (dictOfChildren.TryGetValue(anItem.CategoryID, out children) &&
                children.Count > 0)
                PrintItems(children, dictOfChildren, levelOfIndentation + 1);
        }
    }

It's not really object oriented, but this should give you a hint about the direction to follow.

EDIT:

I saw that you edited the question and that now you have added the SubCategory property. This makes things much simpler and you can simply do:

public static void PrintItems(List<CategoryItem> items)
{
    // call a recursive method passing 0 as level of indentation
    PrintItems(items, 0);
}

public static void PrintItems(List<CategoryItem> items, int levelOfIndentation)
{
    foreach (CategoryItem anItem in items)
    {
        // print the currentItem
        anItem.Print(levelOfIndentation);
        // increment the level of indentation and callk the same method for the children
        PrintItems(anItem.SubCategory, levelOfIndentation + 1);
    }
}
Francesco Baruchelli
  • 7,320
  • 2
  • 32
  • 40
  • my ParentID is an int type sir. I don't understand the line code dictOfChildren["0"]. What does zero means there sir? – chlkdst Jun 04 '12 at 09:08
  • In the definition of CategoryItem in your question ParentID and CategoryID are strings. Anyway, you can change all the strings to int. dictOfChildren["0"] (or dictOfChildren[0] if you use int) returns the list of CategoryItem with ParentID 0, i.e. the root level ones. – Francesco Baruchelli Jun 04 '12 at 09:12
0

Read up on recursion. There are quite a few samples out there. The ones on Wikipedia are simple but the principle is the same: solve the problem on one "level", then call the same method recursively on each sublevel.

Peter Lillevold
  • 33,668
  • 7
  • 97
  • 131