Create a multilevel menu in linq .

In this post we will see how to generate a multilevel menu in Linq or we can as flatten a  hierarchical collection of objects in Linq. For that purpose we are going to make new C# console application.we will design this application such that root node will follow the below shown  pattern.


              Root Node Name ( Count Of Child Node)Is Child of(Parent Node)
                                                           
                                                                  Child Node Name 1
                                                                  Child Node Name 2
                                                                  ...........

Now lets us first of all add two classes to our application to our application.This two class will be Menu and MenuItem . MenuItem class will have properties like id,name,list of children and a parent node to track its root node. Menu class will have properties like id, name and a nullable parent id, because a root node may or may not have any root node.Below i have show the code for Menu and Menuitem class.

1.Menu Class


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
 public class Menu
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int? ParentID { get; set; }

        public Menu(int id, string name, int? parentID)
        {
            this.ID = id;
            this.Name = name;
            this.ParentID = parentID;
        }
    }

2.Menuitem Class


1
2
3
4
5
6
7
public class MenuItem
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public IList<MenuItem> Children { get; set; }
        public MenuItem Patent { get; set; }
    }

Now let us move towards the next step of creating a multilevel menu.so far we have created two classes named Menu and MenuItem .Now it's time to adding content to our menu.I have added members to the menu so that i can get the output as show in below image.



3.Code To Add Menu Members


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 List<Menu> menus = new List<Menu>();
            menus.Add(new Menu(0, "Level 0", null));
            menus.Add(new Menu(1, "Level 1", 0));
            menus.Add(new Menu(2, "Level 1.1", 1));
            menus.Add(new Menu(3, "Level 1.2", 1));
            menus.Add(new Menu(4, "Level 1.2.1", 3));
            menus.Add(new Menu(5, "Level 1.2.2", 3));
            menus.Add(new Menu(6, "Level 1.2.3", 3));
            menus.Add(new Menu(7, "Level 2", 0));
            menus.Add(new Menu(8, "Level 2.1", 7));
            menus.Add(new Menu(9, "Level 2.1.2", 8));
            menus.Add(new Menu(10, "Level 2.2", 7));
            menus.Add(new Menu(11, "Level 2.2.2", 10));
            menus.Add(new Menu(12, "Level 3", 0));
            menus.Add(new Menu(13, "Level 3.1", 12));

As you can see i have created a list of type Menu and then using menu.Add() i have added member to list according to my requirement.This menu will have 3 root level and each root level have one or two children. The count of child will be shown beside the root node as shown in the above figure.

Now let us move towards the most important step of this code and that is the code to flatten this hierarchical menu using linq. Firstly we are going to use SQL like syntax to write the code and then we will convert it to lamda expression.You can use any of the code to generate your menu.

4.SQL Like Query Expression   



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public static IList<MenuItem> GenerateTree(IEnumerable<Menu> collection, Menu rootItem)
        {
            IList<MenuItem> lst = new List<MenuItem>();
            foreach (Menu c in collection.Where(c => c.ParentID == rootItem.ID))
            {
                lst.Add(new MenuItem
                {
                    ID = c.ID,
                    Name = c.Name,
                    Parent = new MenuItem() { ID=rootItem.ID,Name=rootItem.Name},
                    Children = GenerateTree(collection, c)

                });
            }
            return lst;
        }

So for creating our multilevel menu i have created a function named GenerateTree() with return  type List<MenuItem>.If we talk about the working of this function it will accept two parameters Collection of Menu and  rootItem . Inside that we are going to create a new list of children for that root item and add it to that MenuItem list.Here it may happen that the children may have children.To achieve we have to make a recursive call to our GenerateTree() function.Which i have stored in Children.

5.Printing the Menu

Now we have generated the menu according to our requirement,it's time to print it.For that i am going to create a new function named PrintTree() and passing menuitems and a tab space as parameter.It will also be a recursive function as shown below.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 public static void PrintTree(MenuItem menuItems, string tab)
        {
            Console.WriteLine(tab + menuItems.Name + string.Format("({0})",
                             menuItems.Children.Count) + "Is Child of "
                             + string.Format("({0})", menuItems.Parent.Name));
            foreach (var item in menuItems.Children)
            {
                PrintTree(item, tab + "\t");
            }
        }

6.Calling the Functions

Now let's move towards the last step in which we are going to make a call to this two above created function from our main method.


1
2
3
4
5
6
var result = GenerateTree(menus, menus.First());

            foreach (var item in result)
            {
                PrintTree(item, "\t");
            }
   

7.Final Code


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MultiLevelAdvanced
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Menu> menus = new List<Menu>();
            menus.Add(new Menu(0, "Level 0", null));
            menus.Add(new Menu(1, "Level 1", 0));
            menus.Add(new Menu(2, "Level 1.1", 1));
            menus.Add(new Menu(3, "Level 1.2", 1));
            menus.Add(new Menu(4, "Level 1.2.1", 3));
            menus.Add(new Menu(5, "Level 1.2.2", 3));
            menus.Add(new Menu(6, "Level 1.2.3", 3));
            menus.Add(new Menu(7, "Level 2", 0));
            menus.Add(new Menu(8, "Level 2.1", 7));
            menus.Add(new Menu(9, "Level 2.1.2", 8));
            menus.Add(new Menu(10, "Level 2.2", 7));
            menus.Add(new Menu(11, "Level 2.2.2", 10));
            menus.Add(new Menu(12, "Level 3", 0));
            menus.Add(new Menu(13, "Level 3.1", 12));

            var result = GenerateTree(menus, menus.First());

            foreach (var item in result)
            {
                PrintTree(item, "\t");
            }

        }

        public static void PrintTree(MenuItem menuItems, string tab)
        {
            Console.WriteLine(tab + menuItems.Name + string.Format("({0})", 
            menuItems.Children.Count));
            foreach (var item in menuItems.Children)
            {
                PrintTree(item, tab + "\t");
            }
        }

        public static IList<MenuItem> GenerateTree(IEnumerable<Menu> collection, 
         Menu rootItem)
        {
            IList<MenuItem> lst = new List<MenuItem>();
            foreach (Menu c in collection.Where(c => c.ParentID == rootItem.ID))
            {
                lst.Add(new MenuItem
                {
                    ID = c.ID,
                    Name = c.Name,
                    Children = GenerateTree(collection, c)
                });
            }
            return lst;
        }
    }

    public class MenuItem
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public IList<MenuItem> Children { get; set; }
        public MenuItem Patent { get; set; }
    }

    public class Menu
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int? ParentID { get; set; }

        public Menu(int id, string name, int? parentID)
        {
            this.ID = id;
            this.Name = name;
            this.ParentID = parentID;
        }
    }
}

Bingo!!! it's done we have created a multilevel menu using linq sql like query expression in our next post we will edit our code according to lamda expression.If you have learnt some thing from thing article please vote up this article on Code Project.

                                                Article at Code Project

Comments