Рекурсивный цикл по списку MVC 3 - PullRequest
1 голос
/ 03 августа 2011

У меня на сайте есть боковое меню, в котором на данный момент загружено множество элементов списка:

<ul>
    <li>...</li>
    <li>...</li>
    <li>...</li>
</ul>

Теперь мне нужно изменить это, чтобы иметь подэлементы, чтобы он отображал ...

<ul>
    <li>
        <ul>
            <li>...</li>
            <li>...</li>
        </ul>
    </li>
    <li>...</li>
    <li>...</li>
</ul>

У меня есть список таких вещей:

    /// <summary>
    /// Gets the admin menu items.
    /// </summary>
    /// <returns></returns>
    public IQueryable<IAdminMenuItem> GetAdminMenuItems()
    {
        return new List<IAdminMenuItem> {              
            new AdminMenuItem {MenuItemId = "100", DisplayText = "xxx", ParentId = "" ControllerName = "xxx", ActionName = "xxx"},
            new AdminMenuItem {MenuItemId = "101", DisplayText = "xxx", ParentId = "100" ControllerName = "xxx", ActionName = "xxx"},
            new AdminMenuItem {MenuItemId = "102", DisplayText = "xxx", ParentId = "100" ControllerName = "xxx", ActionName = "xxx"},
            new AdminMenuItem {MenuItemId = "200", DisplayText = "xxx", ParentId = "" ControllerName = "xxx", ActionName = "xxx"},
            new AdminMenuItem {MenuItemId = "201", DisplayText = "xxx", ParentId = "200" ControllerName = "xxx", ActionName = "xxx"},
            new AdminMenuItem {MenuItemId = "202", DisplayText = "xxx", ParentId = "200" ControllerName = "xxx", ActionName = "xxx"},
        }.AsQueryable();

Если элемент списка не имеет ParentID, тогда это элемент верхнего уровня. Если это так, то это элемент подэлемента.

У меня есть этот код в настоящее время, чтобы справиться со структурой плоского меню:

<ul>
    @foreach (Avelo.Exchange.WebUI.Domain.Interfaces.IAdminMenuItem item in Model){
       <li><a href="@Url.Action(item.ActionName, item.ControllerName)"><span>@item.DisplayText</span></a></li>
    }
</ul>

Полагаю, мой первый вопрос заключается в том, как бы я обработал элементы подменю в представлении, но я также хотел бы доказать в будущем решение, поскольку оно способно обрабатывать дополнительные подуровни (т.е. три шага вниз, а не два) , Я слышал о рекурсивных циклах, но понятия не имею, как это реализовать. Это хороший путь?

Заранее спасибо

S

1 Ответ

3 голосов
/ 03 августа 2011

У меня была похожая проблема некоторое время назад.Я постараюсь адаптировать свое решение к вашей модели.Я думаю, у вас есть что-то вроде этого:

public interface IAdminMenuItem
{
    string MenuItemId { get; set; }
    string DisplayText { get; set; }
    string ControllerName { get; set; }
    string ActionName { get; set; }
    List<IAdminMenuItem> Children { get; set; }
}

public class AdminMenuItem: IAdminMenuItem
{
    public string MenuItemId { get; set; }
    public string DisplayText { get; set; }
    public string ControllerName { get; set; }
    public string ActionName { get; set; }
    public List<IAdminMenuItem> Children { get; set; }
}

Как вы можете видеть, я изменил ваше свойство ParentId с коллекцией Children, потому что им легче управлять.

По вашему мнению, вы должны заполнить ваше меню (и все подменю) и передать его в представление:

List<IAdminMenuItem> myMenu = new List<IAdminMenuItem>();

myMenu.Add(new AdminMenuItem()
    {
    MenuItemId = "100",
    DisplayText = "Level 1",
    ControllerName = "Home",
    ActionName = "Index",
    Children = new List<IAdminMenuItem>() { 
        new AdminMenuItem() { MenuItemId = "1001", DisplayText = "Level 1a", ControllerName = "Home", ActionName = "Index" },
        new AdminMenuItem() { MenuItemId = "1002", DisplayText = "Level 1b", ControllerName = "Home", ActionName = "Index" }
    }
});

myMenu.Add(new AdminMenuItem()
    {
    MenuItemId = "200",
    DisplayText = "Level 2",
    ControllerName = "Home",
    ActionName = "Index",
    Children = new List<IAdminMenuItem>() { 
        new AdminMenuItem() { MenuItemId = "2001", DisplayText = "Level 2a", ControllerName = "Home", ActionName = "Index" },
        new AdminMenuItem() { MenuItemId = "2002", DisplayText = "Level 2b", ControllerName = "Home", ActionName = "Index" }
    }
});

return View(myMenu);

Это мое представление.Здесь не так много.

@using Mvc3SubMenus.WebUI
@model List<Mvc3SubMenus.IAdminMenuItem>
@{
    ViewBag.Title = "Home Page";
}

@Html.BuildMenu(Model)

Я создал помощника, который будет отвечать за создание вашего меню и всех подменю (с рекурсией):

using System.Collections.Generic;
using System.Web.Mvc;
using System.Text;
using System.Web.Mvc.Html;

namespace Mvc3SubMenus.WebUI
{
    public static class MyHelpers
    {
        public static System.Web.Mvc.MvcHtmlString BuildMenu(this HtmlHelper helper, List<Mvc3SubMenus.IAdminMenuItem> menu)
        {
            return new MvcHtmlString(BuildStringMenu(helper, menu));
        }

        private static string BuildStringMenu(HtmlHelper helper, List<Mvc3SubMenus.IAdminMenuItem> menu)
        {
            var sb = new StringBuilder();
            if ((menu != null) && (menu.Count > 0))
            {
                sb.Append("<ul>");
                foreach (var item in menu)
                {
                    sb.Append("<li>");
                    sb.Append(helper.ActionLink(item.DisplayText, item.ActionName, item.ControllerName));
                    sb.Append("</li>");
                    if ((item.Children != null) && (item.Children.Count > 0))
                    {
                        sb.Append("<li>");
                        sb.Append(BuildStringMenu(helper, item.Children));
                        sb.Append("</li>");
                    }
                }
                sb.Append("</ul>");
            }
            return (sb.ToString());
        }
    }
}

Этохелпер может быть улучшен, и, конечно, кто-то может возразить, что это можно сделать лучше, но у меня не было много времени, чтобы его усовершенствовать.Извините за это.
Вы можете найти код здесь .Проект называется Mvc3SubMenus .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...