Иерархическое меню в представлении на основе родительского дочернего класса - PullRequest
0 голосов
/ 04 сентября 2010

У меня есть ViewModel:

public class Page
{
    public int Id { get; set; }
    public Page Parent { get; set; }
    public string Name { get; set; }
    public string Title { get; set; }
}

Я передаю эту модель в представление, и мне нужно создать иерархическое меню на основе модели:

<ul>
    <li>Page
        <ul>
            <li>Sub Page</li>
        </ul>
    </li>

Через нетОтсутствие усилий. Я не могу понять, как я буду выполнять этот рекурсивный цикл в представлении.

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

Есть идеи?

1 Ответ

1 голос
/ 04 сентября 2010

Есть много способов отображения динамически генерируемых меню, и я опубликую свой способ сделать это, у меня есть два класса Menu & MenuItem (Меню - это просто оболочка для списка MenuItems, которые являются действительными> "реальными" ссылками), а затем у меня есть NavigationViewModel, чтобы обернуть все.

public class MenuItem
{
    public int MenuID { get; set; }
    public int ID { get; set; }
    public String Label { get; set; }
    public String Link { get; set; }
    public Boolean Show { get; set; }

    public MenuItem(int menuId, int id, string label, string link, Boolean show)
    {
        this.MenuID = menuId;
        this.ID = id;
        this.Label = label;
        this.Link = link;
        this.Show = show;
    }
}

//

public class Menu
{
    public int ID { get; set; }
    public string Name { get; set; }
    public List<MenuItem> MenuItems { get; set; }

    public Menu(int id, string name)
    {
        this.ID = id;
        this.Name = name;
        this.MenuItems = new List<MenuItem>();
    }

}

// это NavigationModel, который обернуть все.

public class NavigationModel
{
    public int currentMenuID { get; set; }   
    // used to determine the current displayed Menu to add
    // the "current" class to it. (to be set in the controller)

    public int currentMenuItemID { get; set; } 
    // used to determine the current displayed MenuItem to add
    // the "current" class to it. (to be set in the controller)

    public List<Menu> Menus { get; set; }


    public NavigationModel()
    {
        this.Menus = new List<Menu>();
        // Set Default Menu ( Menu 1 )
        this.currentMenuID = 1;
        // Set Default Menau Item ( None )
        this.currentMenuItemID = 0;
    }
}

// Это пример метода, который создает NavigationModel.

private static NavigationModel BuildNavigationMenu(User currentUser, string rootURL)
    {
        string loginURL = rootURL + "Account/LogOn";

        // Main Menu
        Menu MainMenu = new Menu(1, "Home");
        MainMenu.MenuItems.Add(new MenuItem(1, 1, "Welcome", rootURL, true));
        MainMenu.MenuItems.Add(new MenuItem(1, 2, "How It Works", rootURL + "Home/HowDoesItWork", true));

        // Work Menu
        Menu WorkMenu = new Menu(2, "Work");
        WorkMenu.MenuItems.Add(new MenuItem(2, 1, "Profile", rootURL + "User/Profile/" + currentUser.ID , true));
        WorkMenu.MenuItems.Add(new MenuItem(2, 2, "Customers", "#", true));

        // Add Menus To Navigation Model
        NavigationModel navigationMenu = new NavigationModel();
        navigationMenu.Menus.Add(MainMenu);
        navigationMenu.Menus.Add(HireMenu);

        return navigationMenu;
}

// У меня есть NavigationHelper, который заботится о выводе HTML следующими двумя методами.

Примечание: (это упрощенная версия, так как в моей реализации я использую идентификатор Menu & MenuItem, чтобы найти текущее отображаемое меню и добавить в него «текущий» класс CSS »

public static string DisplayMenu(this HtmlHelper helper, NavigationModel navigationMenu)
{ 
    public static string DisplayMenu(this HtmlHelper helper, NavigationModel navigationMenu)
    {            
        String result = "<ul id='main-nav'>\n";
        foreach(Menu menu in navigationMenu.Menus)
        {
            result +=     "<li>\n";
            result +=         string.Format("<a href='#'> {0} </a>\n",helper.AttributeEncode(menu.Name));
            result +=         "<ul>\n";
            foreach(MenuItem item in menu.MenuItems)
            {
                result += NavigationHelper.ConvertToItem(helper, item);
            }
            result +=         "</ul>\n";
            result +=     "</li>\n";
        }
        result +=     "</ul>\n";

        return result;
    }

    private static string ConvertToItem(this HtmlHelper helper,MenuItem item)
    {
        if (item.Show)
        {
            return string.Format("<li><a href='{0}'>{1}</a></li>\n", helper.AttributeEncode(item.Link), helper.AttributeEncode(item.Label));
        }
        else { return ""; }   
    }
}

наконец, у меня в мастере следующий вызов для отображения меню.

<!-- Navigation -->
<%= Html.DisplayMenu(Model.NavigationMenu) %>

Примечание: у меня есть строго типизированная MasterPage с типом (BaseViewModel), который содержит свойство NavigationMenuвведите NavigationModel

Соединение всего вместе.

В моем примере мне нужно предоставить моим представлениям ViewModel (который наследует мою BaseViewModel) для каждого метода действия, а затем построить меню (используя BuilderМетод, который выполняет большую часть работы, поэтому мне не нужно вводить его заново в каждом методе действия.) Если вы не используете BaseViewModel, вам нужно будет найти другой способ построения модели навигации и затем передать модель навигациина вашу MasterPage.

Для меня я считаю наличие строго типизированной MasterPage, чтобы сделать вещи проще и чище.У ng wilder есть хороший способ реализовать их в своей серии GolfTracker .

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