Using a Custom Data Source for Navigation
Published: May 2010
The chrome for a Microsoft SharePoint Foundation website includes several navigation controls that are bound to data source controls. In each case, the function of the data source control is to retrieve site map nodes or other navigation data from a navigation provider and then pass the data to the navigation control for display.
You can replace some of the data source controls that are behind built-in navigation controls with controls of your own design. This type of customization does not require you to change master pages or deploy custom content pages. The mechanism for replacement is driven entirely by instructions declared in a SharePoint Foundation Feature. For information about creating and deploying Features, see Using Features in SharePoint Foundation.
In the master pages that are installed with SharePoint Foundation, the data source controls behind three important navigation controls are declared as delegate controls, making the data sources eligible for delegate substitution. You can substitute a custom data source for each of the following navigation controls:
Top link bar
To replace the default data source for any of these controls, you must create a Feature and deploy it in a farm solution. The replacement can be one of the data source controls supplied by SharePoint Foundation or the Microsoft .NET Framework, or it can be a custom data source control of your own design. If you write your own data source control, the compiled assembly must be installed in the global assembly cache either by the Feature that declares the delegate substitution or by some other process. The custom control must also have a SafeControl entry in the web.config file. For more information, see How to: Customize a Delegate Control.
Like a placeholder control, a delegate control defines a region in a master page that can be replaced by other content. In this case, the data source control is default content that can be replaced by a substitute control at run time.
For example, the following excerpt from v4.master declares an AspMenu control for the top link bar and a DelegateControl as the data source for the menu. The default content for the delegate is a SiteMapDataSource control.
<SharePoint:AspMenu ID="TopNavigationMenuV4" Runat="server" EnableViewState="false" DataSourceID="topSiteMap" AccessKey="1" UseSimpleRendering="true" UseSeparateCss="false" Orientation="Horizontal" StaticDisplayLevels="2" MaximumDynamicDisplayLevels="1" SkipLinkText="" CssClass="s4-tn"/> <SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource" Id="topNavigationDelegate"> <Template_Controls> <asp:SiteMapDataSource ShowStartingNode="False" SiteMapProvider="SPNavigationProvider" id="topSiteMap" runat="server" StartingNodeUrl="sid:1002"/> </Template_Controls> </SharePoint:DelegateControl>
As with a placeholder control, a delegate control's default content can be replaced by custom content, in this case by another control. What is different with a delegate control is that you do not override the default by adding markup to a content page, as you would with a placeholder. Instead, you make the substitution by deploying a farm solution that includes a Feature that identifies the control you want to replace and the control that you want to replace it with.
The procedure for implementing a Feature for delegate substitution is described in detail in How to: Customize a Delegate Control. In short, you add an element manifest to your Feature, and in the manifest, you declare a Control element that identifies the delegate control and also identifies the assembly and class of the substitution candidate.
For example, the following XML replaces the data source for the top link bar with a custom data source control named Contoso.NavigationDataSource.
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Control Id="TopNavigationDataSource"Sequence="50" ControlClass="Contoso.NavigationDataSource" ControlAssembly="Contoso, Version=22.214.171.124, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <Property Name="SiteMapProvider">SPNavigationProvider</Property> <Property Name="ID">topSiteMap</Property> </Control> </Elements>
The value of the ControlId attribute on the delegate control is TopNavigationDataSource. Therefore, the value of the Id attribute of the Control element must also be TopNavigationDataSource. This links the custom control with the target delegate.
The ControlClass attribute and the ControlAssembly attribute of the Control element tell SharePoint Foundation where to find the candidate control. The signed assembly that contains code for the control must be installed in the global assembly cache.
A key part of the example markup is the Property element that sets the ID attribute of the candidate control to topSiteMap. This is the same value that the AspMenu control uses for its DataSourceID attribute. At run time, the menu control binds to a data source control with that ID. The plan is for it to find the custom control instead of the default control. The custom control, of course, must be derived from the HierarchicalDataSourceControl class because that is what the AspMenu control expects in a data source.
It is possible to have a situation where several Features target the same delegate control. To resolve conflicts, each Feature must specify a sequence number for its substitution candidate, establishing the priority of one candidate over another. At run time, the delegate control accepts the union of control elements declared at the server farm, web application, site collection, and website levels. The control that has the lowest sequence number is added to the control tree. In the case of a sequence tie, the order of controls is arbitrary.
In the example markup for the Contoso.NavigationDataSource control, the value for the Sequence attribute is 50. Although the sequence number for the default data source control is not revealed by its markup, it is safe to assume that it is above 100. If the Contoso control is the only candidate for substitution, it will replace the default data source.