четверг, 30 июня 2011 г.

MVC. Меню с закладками


Захотелось мне меню с закладками – как в стандартной заготовке MVC3 Web Application (Home - About), но чтоб активная вкладка выделять каким то образом – для простоты цветом. В обычном приложении Web Forms это можно сделать довольно несложно на серверной стороне. В приложении MVC3 для меня это оказалось непростой задачей. Поэтому буду ее решать.
Итак, у нас есть список, который и представляет собой меню:
                <ul id="menu">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                </ul>

В CSS-файле есть раздел “TAB MENU”, в котором описывается стиль нашего меню, в том числе есть такое описание:
ul#menu li.selected a {
    background-color: #fff;
    color: #000;
}

Понятно, что описывается стиль активного элемента списка. Теперь надо динамически в зависимости от активной страницы устанавливать стиль selected соответствующему элементу списка. Создадим несложную модель нашего меню (листинг 1).
Листинг 1 – Модель меню
        public class TabMenu
        {
            private TabMenu(string text, string action, string controller)
            {
                Text = text;
                Action = action;
                Controller = controller;
            }

            public static TabMenu Create(string text, string action, string controller)
            {
                return new TabMenu(text, action, controller);
            }

            public string Text { get; private set; }
            public string Action { get; private set; }
            public string Controller { get; private set; }
        }

Как видно, закладка имеет свойства: текст, т.е. что будет написано не закладке, ссылка и контроллер.
Теперь создадим элемент управления HTML для представления (листинг 2).
Листинг 2Компонент для меню
    public static class MenuHtmlHelper
    {
        public static HtmlString TabbedMenu(this HtmlHelper helper, IEnumerable<TabMenu> tabs)
        {
            RouteData route = helper.ViewContext.RequestContext.RouteData;
            string controller = route.GetRequiredString("controller");
            string action = route.GetRequiredString("action");

            string menu = "<ul id=\"menu\">";
            foreach (var tab in tabs)
            {
                if (controller == tab.Controller && action == tab.Action)
                    menu += "<li class='selected'>" + helper.ActionLink(tab.Text, tab.Action,
                        tab.Controller) + "</li>";
                else
                    menu += "<li>" + helper.ActionLink(tab.Text,
                        tab.Action, tab.Controller) + "</li>";
            }
            menu += "</ul>";
            return MvcHtmlString.Create(menu);
        }
    }

Как видно, компонент получает список закладок меню. У той закладки, у которой контроллер и ссылка совпадают с контроллером и ссылкой текущей страницы устанавливается стиль selected для элемента списка. Не забудьте подключить пространства:
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;

Теперь в файле _Layout.cshtml заменяем старое меню на новое (листинг 3).
Листинг 3 – Код меню в представлении
                @Html.TabbedMenu(new List<TabMenu> {

                    TabMenu.Create("Главная", "Index", "Home"),

                    TabMenu.Create("О проекте", "About", "Home")

                })

Чтоб представление «увидело» наш компонент надо подключить:
@using MvcApplication3.Models;

Практически, все. Результат на рисунке 1.
Рисунок 1 – Меню с закладками

Успехов!


4 комментария:

Unknown комментирует...

Здравствуйте. Появился вопрос по меню.
Я хочу сделать что бы было разное меню в зависимости от того, к какой роли относится пользователь.
В стандартной реализации я могу это легко сделать используя конструкцию для отдельных пунктов меню:

if (HttpContext.Current.User.IsInRole("Manager")
{

}


Но используя ваш вариант меню это уже не сделать. Может у Вас есть решение?

dedMazDie комментирует...

Добрый день!
Я не сталкивался. Но ведь для начала нужно знать, какой используется механизм аутентификации на сайте.

Unknown комментирует...

Я использую стандартную asp.net

dedMazDie комментирует...

asp.net - это для разработки.
а мы говорим об аутентификации. как я вижу, Ваш сайт использует стандартную аутентификацию на основе Membership API (это происходит через кнопочку "Вход"). В нем есть и роли, но как ими пользоваться, я не знаю - не приходилось. Будет время, постараюсь разобраться.