tony testa posted on November 16, 2009 03:33

This past weekend I presented at the SharePoint Satuday event in Cleveland.  As with all the SharePoint Saturday events, they have gone off pretty smoothly and I was glad that I could be a part of the event.  I got a chance to talk to some of the other speakers as well and met some really cool people out there.

My session was on doing Enterprise development and deployment with SharePoint 2010 and I hope that I was able to pass along some knowledge I’ve gained over the years.


Presentation Link : Code/Slides

Posted in: Sharepoint , Personal Projects  Tags:

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 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.

My initial custom approach I thought would be pretty simple, so I added a content editor webpart to the page and began dusting off my javascript skills and trying to edit the DOM.  After about a day, I was ready to pull my hair out for 2 reasons, first being that I couldn’t solve it, and the second was that javascript just flat out blows if you aren’t doing it 5 days a week.  The basic javascript approach was something that I though would work best since all it needed was a content editor webpart and pasting in some code, I could then add that code to the master page.

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 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 to do the replacement.

Here is what the browser file looks like:

  <browser refID="Default">
      <adapter controlType="Microsoft.SharePoint.WebControls.AspMenu, Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
      adapterType="DTCubed.Navigation.MenuAdapter" />


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:

namespace DTCubed.Navigation
    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);
            while (stringFound)
                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). (429.90 kb)

What the hell is the "SharePoint Ninja Toolkit" you ask?  It is going to be where I plan to release the countless small little utility apps/features that I've written over my SharePoint development experiences.  Almost every project I've worked on I end up with small little apps or chunks of code that end up sitting around that I reference from time to time.  I figured, I might as well polish these up a tad and release them out there for others to enjoy.  Hopefully it will save someone the headache of having to do it themselves, or if anything, serve as a learning tool.

Check it out over at CodePlex. (Right now its unpublished, but by the end of the week i'll have at least 1 or 2 small utilities up there to start it out.)

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2017 Tony Testa's World