I am writing a website with Visual Studio 2008 and ASP.NET 3.5. I have a masterpage set up to simplify the layout and to keep the content pages for content rather than content and layout.

The navigation is list, css'd so it looks like a bar. In order to highlight the page on the bar, the list item needs to look like this <li id="current">. I do not want to use <asp:ContentPlaceHolder> if I can avoid it. Is there some code I can add to each of my pages (or just to the masterpage?) to accomplish this or am I stuck using <asp:ContentPlaceHolder>'s?


The use or non use of ContentPlaceHolder will not affect which element has the id="current" set on it.

You will have to look at some method, either in your codebehind for the master page, a javascript function or something else when rendering the menu component to properly add the id="current" to the list when it is created.

Mitchel Sellers

I would use javascript to accomplish this. In css, change your #current to be a class (.current) and then have id's on each of your ListItems that you create. Then using RegisterStartupScript, call a javascript method that gets the appropriate ListItem and assigns it a style of current. Using Prototype, this would look like $('MyPageLi').className = 'current'.

so basically have each item have unique classes (i suppose i could name them like `<li class="nav_faq">` for instance) and then when i nav to a different page call javascript to change the "nav_faq" to current?
No, give them each unique _IDs_, and a common class. Then you can use javascript to get all elements with that class and make sure none of them have the current class, then get the single element with the particular id for the current page and add the current class to it.
Joel Coehoorn
+7  A: 

Add a property to your master page called Page Section

public string PageSection { get; set; }

Add a MasterType page directive to the top of your content pages

<%@ MasterType VirtualPath="~/foo.master" %>

In your content page code behind, set the PageSection property of the master page

Master.PageSection = "home";

In your master page, make the body tag a server tag

<body ID="bodyTag" runat="server">

In the master page code behind, use that property to set a class on the body tag

bodyTag.Attributes.Add("class", this.PageSection);

Give each of your nav items a unique ID attribute.

In your css, change the display of the nav items based on the current page class

.home #homeNavItem,
.contact #contactNavItem
    color: #f00; 
John Sheehan
I am using VB.NET as the backend rather than C#, and to be honest I know little about C#. when making the property, what do I need to put anything within get...end get // set...end set to make it work properly?
oh, i already have the css set. all that needs to change to make the link selected is having the id="current" in the list item tag.
Then in your master page code behind, add the 'current' attribute on the list item based on the page section.
John Sheehan
For the VB property, you just need a simple string property. I don't know the syntax off hand. The C# syntax I used is C# 3.0's new automatic properties.
John Sheehan
I must be doing something wrong, I cannot get the property to show up on my content pages. Master.PageSection does not work, nor does Me.PageSection. Property is declared as "Public Shared Property PageSection() As String"
Get rid of 'Shared'
John Sheehan
Alright, did that and it is still not showing up. I added the MasterPage virtual path but still no dice. Very strange.
email me at johnsheehan at gmail and I'll see if I can help you more
John Sheehan
Quick question: I'm trying to use this in an ASP.NET MVC site. How do I add the property to my master page? I don't have a master page codebehind defined - all the other master page code is inline in `<% %>` blocks.
Maxim Zaslavsky
This will not work for an MVC site. For MVC, just put the page section in ViewData and access it via <%=ViewData["PageSection"]%> from the master.
John Sheehan
+2  A: 

It's a better semantic match and likely an easier variable to set to keep the navigation using the same classes or ids everywhere and only alter the body element's id to match:

<li id="homeNav">home</li>
<li id="blogNav">blog</li>

and then on each page...

<body id="home">
<body id="blog">

And in the css:

#home #homeNav {background-image:url(homeNav-on.jpg);}
#blog #blogNav {background-image:url(blogNav-on.jpg);}
+6  A: 

Have you considered using a Web.sitemap file? It makes it real easy. If your sitemap file looks like this...

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="" >
    <siteMapNode url="~/Default.aspx" title="Home"  description="" />
    <siteMapNode url="~/Blog.aspx" title="Blog"  description="" />
    <siteMapNode url="~/AboutUs.aspx" title="AboutUs"  description="" />

...then you can do this in your master page to achieve the results you want:

<asp:SiteMapDataSource ID="sitemapdata" runat="server" ShowStartingNode="false"  />
<ul id="navigation">
    <asp:Repeater runat="server" ID="navrepeater" DataSourceID="sitemapdata">
            <li class="<%# SiteMap.CurrentNode.Equals(Container.DataItem) ? "activenav" : "inactivenav" %>"><a href="<%# DataBinder.Eval(Container.DataItem, "url") %>"><%# DataBinder.Eval(Container.DataItem, "title") %></a></li>

The current page's LI will have a class of "activenav" (or whatever you decide to use), and the others will have a class of "inactivenav". You can write your CSS accordingly. This is the technique I use on my site and it works great.

Joshua Carmody
This is the best route to go, in my humble opinion.

Using the PageSection Property in the Master page submitted by John Sheehan works very well for me. Thank you so much for the solution!

Kam Cheung

How about creating a protected string property in your masterpage code class? Override the OnLoad:

protected string _bodyId;

protected override void OnLoad(EventArgs e)
    _bodyId = "your css id name";

Then in your masterpage aspx:

<body id="<%= _bodyId %>">

Then you don't have to mess with your CSS, especially useful if the CSS came from a design agency.