Here was my problem; I had a SharePoint site which served as a companies intranet and thus had quite a few sub sites and therefore the top navigation bar had quite a few tabs. Obviously this isn’t an the wall scenario and I’m sure that most people can relate if they’ve seen a company use SharePoint as their main intranet. The issue was the number of tabs that they had on their top navigation caused the browser, even on LARGE monitors, to have horizontal scroll bar. This wasn’t cutting it for the client and they needed a solution to wrap the tabs so that their would be multiple lines of intranet site tabs.
I wasn’t originally the developer assigned to this task. The original developer took the typical approach and looked around to see if we this problem had been previously solved. The telerik asp.net controls were identified as a solution since it had a navigation control that looked promising. I was told that this control would automatically wrap the tabs. Of course…when I was put on the project and tried out the telerik control…i didn’t wrap and I started to shit myself since I was only given a short timeframe to complete the task since the control was SUPPOSED to work. After I played around a bit as well, I noticed that the telerik navigation control really didn’t style itself well with SharePoint, it looked out of place, even with its “office” theme.
Being that I had recently learned to love jQuery, I gave that a shot but frankly I am just not that well versed with jQuery to accomplish what I needed, in addition I would have to include jQuery into the master page and thus slow down the render of each page (which was already a complaint of the client).
After roaming the net I stumbled across a little known ASP.NET “browser” file which basically allows you to tell the asp.net web application that for any control that is using X class, pass it through to your adapter class, through the use of control adapters. All you need is the class you want to inject, and the browser file which tells asp.net to do the replacement.
Here is what the browser file looks like:
<adapter controlType="Microsoft.SharePoint.WebControls.AspMenu, Microsoft.SharePoint, Version=126.96.36.199, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
As you can see I am telling my web application that for the AspMenu control, from the SharePoint.WebControls namespace, replace it with my custom MenuAdapter.
The code for my MenuAdapter class is pretty simple:
public class MenuAdapter : ControlAdapter
private string MAX_TAB_COUNT = ConfigurationManager.AppSettings["MaxTabCountPerLine"].ToString();
protected override void Render(System.Web.UI.HtmlTextWriter writer)
StringBuilder sb = new StringBuilder();
StringWriter stringWriter = new StringWriter(sb);
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
string txt = sb.ToString();
txt = txt.Replace("<td style=\"width:0px;\"></td>","");
string txtToFind = "<td onmouseover=\"Menu_HoverStatic(this)\" onmouseout=\"Menu_Unhover(this)\" onkeyup=\"Menu_Key(this)\" id=\"zz1_TopNavigationMenun";
bool stringFound = true;
int txtFoundIdx = 0;
int currentTabCount = 0;
int currentTabIdx = 0;
int tabCount = 0;
//check the tab count config setting, if it exists, set our variable, if not, default it.
tabCount = 12;
tabCount = Int32.Parse(MAX_TAB_COUNT);
stringFound = false;
txtFoundIdx = txt.IndexOf(txtToFind, currentTabIdx);
if (txtFoundIdx > 0)
stringFound = true;
currentTabIdx = txtFoundIdx + 10;
if (currentTabCount == tabCount)
currentTabCount = 0;
txt = txt.Insert(txtFoundIdx, "</tr><tr>");
What is going on here is that I am inheriting from the ControlAdapter class and making my own class where I can modify the Render method, basically modifying the output of the AspMenu class. As you can see in the Render method, I am taking the HTML output of the AspMenu class, searching it, and breaking it after X number of tabs. I also have it reading from the Web.Config to tell how many tabs to break at so that you can easily change it to meet your needs.
All that is needed to deploy this is to deploy the DLL to the GAC (or the BIN), put the .browser file into the “App_Browser” directory, add the web.config app key for tab count, and do an IIS reset. The beauty of this is that it will work on any site collection underneath the web application and there are no modifications needed to the sites themselves or master pages.
Below is the zipped up code…technically its packaged as a feature, but the feature doesn’t actually deploy cleanly (I am working on fixing that at the moment).
DTCubed.Navigation.zip (429.90 kb)