ASP.NET MVC and navigation

2019-05-26 10:02发布

问题:

I'm trying to learn ASP.NET MVC, and I want to have menus highlighted on the item that is currently selected. I know I did this before in web forms (although I don't actually remember how at the moment, but somehow with the sitemap). But how can this be done in MVC?

It seems like such a basic thing it should be simple to do in MVC? Sure, I can do it by adding CSS rules that are coupled between a body id and an li id from the menu (#home #homeli [style as current]), but it seems that would quickly become unwieldy, especially if there are also a lot of sub menus besides the main navigation (in several of the sub pages I have a sub menu in a contentplaceholder. BTW, I guess that's the only way to do it in MVC? In web forms the sub menus too could be handled by the sitemap, but I haven't seen a way to do this in MVC...)

Any suggestions?

回答1:

Here is a tutorial that provides a very clean way to achieve this kind of menu:

http://www.dev102.com/2009/04/14/creating-a-tabbed-menu-control-for-aspnet-mvc/

The magic bit figuring out whether or not a menu item is active happens in the helper method that renders the items:

public static class MyHtmlHelper
{
   public static string TabbedMenu(this HtmlHelper helper, IEnumerable<MenuTab> tabs)
   {
       var route = helper.ViewContext.RequestContext.RouteData;
       //This is the current controller
       var controller = route.GetRequiredString("controller");
       var action = route.GetRequiredString("action");
       var menu = "\n\n<ul id=\"menu\">";

       foreach (var tab in tabs)
       {
           //if the menu controller and action match current controller and action, mark it as selected
           if (controller == tab.Controller && action == tab.Action)
               menu += "\n\t<li>" + helper.ActionLink(tab.Text, tab.Action,
               tab.Controller, new { @class = "selected" }) + "</li>";
           else
               menu += "\n\t<li>" + helper.ActionLink(tab.Text,
               tab.Action, tab.Controller) + "</li>";
       }
       menu += "\n</ul>\n\n";
       return menu;
   }
}

MenuTab class:

public class MenuTab
{
    private MenuTab(string text, string action, string controller)
    {
        Text = text;
        Action = action;
        Controller = controller;
    }

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

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

Usage:

<%= Html.TabbedMenu(new List<MenuTab> {
    MenuTab.Create("Home", "Index", "Home"),
    MenuTab.Create("About", "About", "Home"),
    MenuTab.Create("Services", "Services", "Home"),
    MenuTab.Create("Pricing", "Pricing", "Home"),
    MenuTab.Create("Contact", "Contact", "Home")
}) %>


回答2:

Menu item per Controller

@{
    var currentController = (string)ViewContext.RouteData.Values["controller"];

    Func<string, object> htmlAttributesFactory =
        controller => currentController == controller ? new {@class = "selected"} : null;

    Func<string, string, MvcHtmlString> menuItemFactory =
        (title, controller) =>
        Html.RouteLink(
            title,
            new {controller},
            htmlAttributesFactory(controller)); 


}

@menuItemFactory("Home", "Home")
@menuItemFactory("Pending", "Pending")