Reputation: 11607
I want to make a navigation bar for my website. This bear will have various links to pages, and the link to the page the user is currently on should be highlighted.
At the moment I have html like this:
<div id="navbar" runat="server">
<a href="/" runat="server" id="lnkHome">Home</a> |
<a href="~/info.aspx" runat="server" id="lnkInfo">Info</a> |
<a href="~/contacts.aspx" runat="server" id="lnkContacts">Contacts</a> |
<a href="~/settings.aspx" runat="server" id="lnkSettings">Settings</a>
</div>
And code in my PageLoad event like this:
//Show the currently selected page
String filename = System.IO.Path.GetFileNameWithoutExtension(Request.Path).ToLower();
if (filename == "default")
lnkHome.Attributes.Add("class", "selected");
else if (filename == "info")
lnkInfo.Attributes.Add("class", "selected");
else if (filename == "contacts")
lnkContacts.Attributes.Add("class", "selected");
else if (filename == "settings")
lnkSettings.Attributes.Add("class","selected");
This is difficult to maintain. If I want to add a link, I have to give it an id, and add info for it to the if statement. I want a more flexible system, where I can dynamically add links to the navigation bar, and have them appear highlighted when the user is on the right page.
How do I do this? Is it possible to search navbar
for child elements based on their href
property? It would be best if these elements did not have to have the runat="server"
attribute, so they can be treated just as regular HTML. Or is there a different implementation I should consider?
Upvotes: 4
Views: 1624
Reputation: 14971
I've run into many situations where I need to find a descendant or ancestor. In response to this, I've written some extension methods which help me out a lot. I would suggest using these with the following code:
Required using statements:
using System.Collections.Generic;
using System.Web.UI;
Extension methods:
/// <summary>
/// Finds a single, strongly-typed descendant control by its ID.
/// </summary>
/// <typeparam name="T">The type of the descendant control to find.</typeparam>
/// <param name="control">The root control to start the search in.</param>
/// <param name="id">The ID of the control to find.</param>
/// <returns>Returns a control which matches the ID and type passed in.</returns>
public static T FindDescendantById<T>(this Control control, string id) where T : Control
{
return FindDescendantByIdRecursive<T>(control, id);
}
/// <summary>
/// Recursive helper method which finds a single, strongly-typed descendant control by its ID.
/// </summary>
/// <typeparam name="T">The type of the descendant control to find.</typeparam>
/// <param name="root">The root control to start the search in.</param>
/// <param name="id">The ID of the control to find.</param>
/// <returns>Returns a control which matches the ID and type passed in.</returns>
private static T FindDescendantByIdRecursive<T>(this Control root, string id) where T : Control
{
if (root is T && root.ID.ToLower() == id.ToLower())
{
return (T)root;
}
else
{
foreach (Control child in root.Controls)
{
T target = FindDescendantByIdRecursive<T>(child, id);
if (target != null)
{
return target;
}
}
return null;
}
}
Your C# code-behind:
var fileName = Path.GetFileNameWithoutExtension(Request.Path);
var controlId = "lnk" + fileName;
var anchorTag = navbar.FindDescendantById<HtmlAnchor>(controlId);
anchorTag.Attributes.Add("class", "selected");
Upvotes: 1