by

How to Customize My Links Control in SharePoint

User adoption is  everything in a successful SharePoint implementation and one of the main things to attract users to use the site is by customizing the site according to their needs or a previous product. In a lot of cases this never gets 100% done and then one day when a power users is browsing the site he can see things like that: A reference to the Microsoft product inside their own organization.

customize-mylinks-control-sharepoint-0
My SharePoint Sites link being displayed in the client screen
The ideal situation is for a product to be vendor/technology agnostic. From the user's point of view, he doesn't care what is the framework or the company; he just want to have access to his tools.
So, how to customize that My Links control from SharePoint web sites?
Answer: We will create a SharePoint feature to place our own ASCX control in the page instead the default SharePoint OOTB control.
First let's inspect how is this control implemented. If you open the homepage using SharePoint Designer and search for that specific part of the code you will notice that control is a SharePoint DelegateControl.
customize-mylinks-control-sharepoint-1
A delegate control is one of the coolest aspects of the SharePoint ecosystem. This control has the ability to render any user custom ASP.NET controls inside SharePoint pages on the fly by just changing the ControlId.
If we come back to our case, what that line is doing is: at this exact position, render the control called 'GlobalSiteLink2'.
Now remember these functionality are available to the application by features. Let's go then and search for the key 'GlobalSiteLink2' in the TEMPLATE\FEATURES folder on the 12 hive.
customize-mylinks-control-sharepoint-2

You will discover that there is a feature called 'MySite' there which implements the actual control.
Open the file MySiteFeatureElements.xml and you will see this:
   1 <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    2   <Control Id="GlobalSiteLink1" Sequence="100" ControlSrc="~/_controltemplates/mysitelink.ascx" />
    3   <Control Id="GlobalSiteLink2" Sequence="100" ControlSrc="~/_controltemplates/mylinks.ascx"/>
    4   <Control Id="ProfileRedirection" Sequence="100" ControlSrc="~/_controltemplates/mysiteredirection.ascx"/>
    5 </Elements>
there it is our control Id='GlobalSiteLink2' and its source is in a file called 'mylinks.ascx'.
Next step, we need to find out the mylinks.ascx control. For that you have to navigate to the user controls folder at the 12 hive ($\TEMPLATE\CONTROLTEMPLATES). There you will see all the user controls available to SharePoint.  Let's have a look at the source code of this control.

Code Snippet
  1. <%@ Control className="MyLinksUserControl" Language="C#" Inherits="Microsoft.SharePoint.Portal.WebControls.MyLinksUserControl&#44;Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  2. <%@ Register Tagprefix="OSRVWC" Namespace="Microsoft.Office.Server.WebControls" Assembly="Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  3. <%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  4. <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  5. <table><tr>
  6. <td class="ms-globallinks"><SPSWC:MyLinksMenuControl id="MyLinksMenu" runat="server" /></td>
  7. <td class="ms-globallinks"><asp:Literal id="hlMySiteSpacer" runat="server" /></td>
  8. </tr></table>

We now see that MyLinksMenu is an object of MyLinksMenuControl, and this class is defined inside Microsoft.SharePoint.Portal.WebControls.Dll

customize-mylinks-control-sharepoint-6 
That's good news. We find a method called LoadMenuItems() that returns an array list of menu items.
Ok. At this point we have to question ourselves something very important: We should avoid as much as we can interfere during the natural course of SharePoint's behavior. Given that method call we assume that instead modifying it we should be able to configure that string somewhere in the configuration files and then LoadMenuItems() would just return the items with the new label. Would not be the easier and most logical way for Microsoft and everybody else to modify that value?
As much as this proposition might sound correct, unfortunately the answer is no. That string is hardcoded somewhere into the SharePoint source code as a resource file and embedded within the DLL. If you try to inspect that, here's what you get:
customize-mylinks-control-sharepoint-7
The funny thing is that many other areas and messages and labels across the whole SharePoint platform can be configured by updating the resource files, makes you wonder:  "why they did not used the same approach here?"
So, how to fix that?
Using the same delegate control to render your control instead of the out of the box one; and to avoid breaking the natural SharePoint flow of things we are going to create a control inheriting from the OOTB SharePoint MyLinksMenuControl.
We should start by creating a solution that looks like this with WSPBuilder. We will mimic the complete structure for MyLinks.ascx's feature and give it another name.
customize-mylinks-control-sharepoint-5 
 
Compile the solution for the very first time and then extract the public key token. Go to the folder where the DLL is located and execute this command.
customize-mylinks-control-sharepoint-8
Copy and paste the public key token displayed in the screen in our next step, into the ascx source code.
Now will create a similar ascx control just like the original one, but instead of using the webcontrols part we will be using our own MyCustomLinksMenu.ascx
Code Snippet
  1. <%@ Control className="MyLinksUserControl" Language="C#" Inherits="Microsoft.SharePoint.Portal.WebControls.MyLinksUserControl&#44;Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  2. <%@ Register Tagprefix="OSRVWC" Namespace="Microsoft.Office.Server.WebControls" Assembly="Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  3. <%@ Register Tagprefix="SPSWC" Namespace="CustomizeMyLinks" Assembly="CustomizeMyLinks, Version=1.0.0.0, Culture=neutral, PublicKeyToken=995e4d025d306cec" %>
  4. <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  5. <table><tr>
  6. <td class="ms-globallinks"><SPSWC:MyCustomLinksMenu id="MyLinksMenu" runat="server" /></td>
  7. <td class="ms-globallinks"><asp:Literal id="hlMySiteSpacer" runat="server" /></td>
  8. </tr></table>

Let's go to www.newguid.net and get ourselves a brand new Guid for the feature. Keep this Guid, we will use it in our next step to assign it to the feature Id.
 customize-mylinks-control-sharepoint-4
This is how it will looks like our new feature.XML.
    1 <?xml version="1.0" encoding="utf-8"?>
    2 <Feature Id="{6fed26c0-57d3-4237-afd7-722c5c13a147}"
    3         Title="Customize MyLinks menu control"
    4         Description="Renames the mention to SharePoint from the MyLinks control, to make the website more vendor agnostic"
    5         Version="1.0.0.0"
    6         Hidden="FALSE"
    7         Scope="Site"
    8         xmlns="http://schemas.microsoft.com/sharepoint/"
    9         ImageUrl ="">
   10   <ElementManifests>
   11     <ElementManifest Location="elements.xml"/>
   12   </ElementManifests>
   13 </Feature>


And this is our new elements.XML which is a copy from MySiteFeatureElements.XML. Note the control GlobalSiteLink2 pointing to our brand new ascx control.
    1 <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    2   <Control Id="GlobalSiteLink1" Sequence="100" ControlSrc="~/_controltemplates/mysitelink.ascx" />
    3   <Control Id="GlobalSiteLink2" Sequence="100" ControlSrc="~/_controltemplates/MyCustomLinksMenu/MyCustomLinksMenu.ascx"/>
    4   <Control Id="ProfileRedirection" Sequence="100" ControlSrc="~/_controltemplates/mysiteredirection.ascx"/>
    5 </Elements>


And here's the code for the custom control. The comments in the code are self-explanatory.
    1 using System.Collections;
    2 using Microsoft.SharePoint.Portal.WebControls;
    3 using Microsoft.SharePoint.WebControls;
    4 
    5 namespace CustomizeMyLinks
    6 {
    7     /// <summary>
    8     /// Customize the current MyLinks menu control
    9     /// and rename the link 'My SharePoint Sites' to 'Visit Your Sites'
   10     /// </summary>
   11     public class MyCustomLinksMenu : MyLinksMenuControl
   12     {
   13         /// <summary>
   14         /// Loads the menu items.
   15         /// </summary>
   16         /// <returns>a <see cref="ArrayList"/> with
   17         /// all the menu items from <see cref="MyLinksMenuControl.LoadMenuItems"/></returns>
   18         protected override ArrayList LoadMenuItems()
   19         {
   20             // make sure you will call the out of the box method that generates
   21             // the default items in SharePoint
   22             var currentMenuItems = base.LoadMenuItems();
   23 
   24             if ((currentMenuItems != null) && (currentMenuItems.Count>0))
   25             {
   26                 // now that you have the items, you can manipulate them the way you want
   27                 SubMenuTemplate customMenuTemplate;
   28                 using (customMenuTemplate = (SubMenuTemplate) (currentMenuItems[0]))
   29                 {
   30                     if (customMenuTemplate != null)
   31                     {
   32                         customMenuTemplate.Text = "Visit Your Sites"; // or any other text you want here
   33                         currentMenuItems.RemoveAt(0);
   34                         currentMenuItems.Add(customMenuTemplate);
   35                         // you can also try currentMenuItems.InsertAt(0,customMenuTemplate);
   36                     }
   37                 }
   38             }
   39             return currentMenuItems;
   40         }
   41     }
   42 }

Compile. Build the package with WSPBuilder and deploy the feature to the 12 hive, activate the feature in the web site and voilá! You will see the link customized.
 customize-mylinks-control-sharepoint-3
See you later

By

4 comments:

  1. AnonymousJuly 13, 2010

    Quite right! It is good thought. I call for active discussion.

    ReplyDelete
  2. Thanks for this nice article, it's very famous blogs

    ReplyDelete
  3. Chris JenkinsNovember 04, 2011

    Great blog!
    Im trying this with MOSS 2007, Ive kicked your sol'n around but havent had much luck, everything looks to be in the right spot. Any debugging suggestions?

    ReplyDelete
  4. AnonymousMay 09, 2012

    Thanx! but to make this work, i had to change feature.xml Scope="Farm"

    ReplyDelete