In the default asp.net mvc project, in the Site.Master file, there is a menu navigation list:
Try
Should work fine !!!
EDIT : REMOVED IN BETA1
Removed the ViewName property from the ViewContext class.
Inside a view, you can get the current action name with:
ViewContext.RouteData.Values["action"].ToString()
I made myself a helper method to handle this type of thing. In the code behind of my master page (could be pushed of to an extension method ... probably a better approach), I put the following code.
protected string ActiveActionLinkHelper(string linkText, string actionName, string controlName, string activeClassName)
{
if (ViewContext.RouteData.Values["action"].ToString() == actionName &&
ViewContext.RouteData.Values["controller"].ToString() == controlName)
return Html.ActionLink(linkText, actionName, controlName, new { Class = activeClassName });
return Html.ActionLink(linkText, actionName, controlName);
}
Then, I just call it in my page like so:
<%= ActiveActionLinkHelper("Home", "Index", "Home", "selected")%>
In MVC 3 Razor View Engine, you can do it as:
@{string ctrName = ViewContext.RouteData.Values["controller"].ToString();}
<div id="menucontainer">
<ul id="menu">
<li @if(ctrName == "Home"){<text> class="active"</text>}>@ Html.ActionLink("Home", "Index", "Home")</li>
<li @if(ctrName == "About"){<text> class="active"</text>}>@ Html.ActionLink("About Us", "About", "Home")</li>
</ul>
</div>
My sample worked when I have two pages as: Home/About and its controller has same name Index, so I get controller Name for distinction insteed of action. If you want to get action, just replace with following:
@{string ctrName = ViewContext.RouteData.Values["action"].ToString();}
The fact that your View has to know about your controller's actions is breaking with the MVC pattern. Perhaps your controller could pass some "control" information to the view to ultimately allow it to accomplish the same thing, the only difference is who is in charge.
Like in your controller's action you could:
public ActionResult Index(){
ViewData["currentAction"] = "Index";
//... other code
return View();
}
Then over in your view you could:
<% if( ((string)ViewData["currentAction"]) == "Index" {%> <!- some links --><% } %>
<% if( ((string)ViewData["currentAction"]) == "SomethingElse" {%> <!- some links --><% } %>
However, the more I think about it the more I question why you are using the same View for multiple actions. Is the view that similar?
If the use case justifies it then go with my above suggestion. But otherwise perhaps you could break things out into multiple views (one for each controller action) and the problem solves itself.
Based on the previous answers, here is what my current solution is for the same issue:
In the master page I give each li an id that corresponds to the controller and the action, since this should be known from the ActionLink. I was previously doing this with the page title but this helps with organization.
Site.Master:
<ul id="menu">
<li id="menuHomeIndex" runat="server"><%= Html.ActionLink("Home", "Index", "Home") %></li>
<li id="menuHomeAbout" runat="server"><%= Html.ActionLink("About Us", "About", "Home") %></li>
</ul>
Site.Master.cs:
// This is called in Page_Load
private void SetActiveLink()
{
string action = "" + ViewContext.RouteData.Values["controller"] + ViewContext.RouteData.Values["action"];
var activeMenu = (HtmlGenericControl)Page.Master.FindControl("menu" + action);
if (activeMenu != null)
{
activeMenu.Attributes.Add("class", "selected");
}
}
It's more work than the inline code but I think it's cleaner and also lets you have actions with the same name in different controllers. So if you add more menu items with different controllers, not all actions named Index will be highlighted in the menu.
If anyone sees issues with this approach please let me know.