Click here to Skip to main content
15,887,485 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi
I am following this link Loop Through Multi-Level Dynamic Menus in Asp.Net MVC

It makes really sence, but now I am stuck on this. I makes an error when I have a method inside the LINQ querry. It cannot convert IEnumerable to an genericlist? How do I solve this problem. Have try to set .ToList() after the method.

I have made my Viewmodel from my categories model

C#
public class Category
    {
        public int CategoryId { get; set; }

        [Required(ErrorMessage = "Fill in a Name")]
        public string Name { get; set; }

        public int? ParentCategoryId { get; set; }
        public Category ParentCategory { get; set; }

        public virtual ICollection Listings { get; set; }
    }

To this Viewmodel :

C#
public class MenuViewmodel
    {
        public int MenuId { get; set; }
        public string Name { get; set; }

        public List Children { get; set; }
    }

On my controller

<pre lang="c#">
[ChildActionOnly]
        public ActionResult Menus()
        {
            
            List menusource = categoriesRepository.AllIncluding().ToList(); // Get menus from here
           var model = CreateVM(0, menusource); //Transform it into the viewmodel
            return PartialView("_Menu");
        }
        public IEnumerable CreateVM(int parentId, List source)
        {
            
            var model = (from p in categoriesRepository.AllIncluding() select p).ToList();
            model = from m in model where m.CategoryId == parentId select new
                  MenuViewmodel() {
                MenuId = m.CategoryId,
                Name = m.Name,
                Children = CreateVM(m.CategoryId, source)

            };

            return model;
        }
Posted
Comments
DotNetSteve 27-Nov-15 19:41pm    
in the ActionResult Menus() function, what it the purpose of assigning CreateVM to model. model is not subsequently used (not passed to view)

the first two lines of CreateVM doesn't look correct to me.
tina_overgaard 28-Nov-15 12:31pm    
I am just following the link above, because I am an newbie. So what is my next step?

1 solution

I am going to re-order the code a bit so you can see relationship more clearly:

C#
public ActionResult Menus(){
    List<Menu> menusource; // get your menus here
    ViewBag.Menus = CreateVM(0, menusource);  // transform it into the ViewModel
    return View();
}


The block above is creating an empty list and passing to CreateVM, CreateVM returns a populated list which is assigned to the the View using the Viewbag

@{ 
    var menusList = ViewBag.Menus as IEnumerable<MenuViewModel>; 
    Html.RenderPartial("MenuPartial", menuslist);
}


The menulist is passed as ViewBag.Menus and is passed as a list of menu items into the partial view called "MenuPartial"

The partial view looks like this:

HTML
@model IEnumerable<MenuViewModel>

@foreach (var menuitem in model)
{
    <ul>
        <li>
            <h1>@menuitem.Name</h1>
            @{
                Html.RenderPartial("MenuPartial", menuitem.Children);
            }
        </li>
    </ul>
}


The @model is populated when rendering the view -
Html.RenderPartial("MenuPartial", menuslist);


For each menu item it will display the current list items (menueitem.Name) and then the items children list (going deeper into the hierarchy) and their children and their children etc.

The last part to address is the CreateVM function.

C#
public IEnumerable<MenuViewModel> CreateVM(int parentid, List<Menu> source)
{
    return from men in source
           where men.ParentId = parentid
           select new MenuViewModel(){
                      MenuId = men.MenuId, 
                      Name = men.Name
                      // other properties
                      Children = CreateVM(men.MenuId, source)
                  };
}


This routine is also recursively building a list to be displayed. I have underlined where the function calls itself. So in the same way it is building up the list to eventually pass back to the calling routine.

I think what might be missing is how the data is loaded to create the hierarchy. The following is psuedo code but should be illustrative:

List<menuviewmodel> mm = new List<menuviewmodel>();
mm.add(new MenuViewmodel() {id=1, name="one"});
//now there is one item at the root level
mm.add(new MenuViewmodel() {id=2, name="two"});
//now there are two at first level.
</menuviewmodel></menuviewmodel>


Lets add a subitem to the first item

C#
mm[0].Children = new List<menuviewmodel>();
mm[0].Children.add(new MenuViewmodel() {id=10, name="One - One"});
</menuviewmodel>


Now you have a list of MenuViewmodel which also contains another list under the first item of MenuViewmodel.

Hope this helps.
 
Share this answer
 
Comments
[no name] 29-Nov-15 13:52pm    
Even I can't follow all in details, I think you made a good job, answering the question. So I let a 5 here.
tina_overgaard 30-Nov-15 8:16am    
Thank you DotNetSteve for that explanation :-)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900